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.

Module.cs 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. using System.Reflection;
  8. using System.Threading;
  9. using Combot.Configurations;
  10. using Combot.Databases;
  11. using Combot.IRCServices;
  12. using Newtonsoft.Json;
  13. namespace Combot.Modules
  14. {
  15. public class Module
  16. {
  17. public string Name { get; set; }
  18. public string ClassName { get; set; }
  19. public bool Enabled { get; set; }
  20. public List<string> ChannelBlacklist { get; set; }
  21. public List<string> NickBlacklist { get; set; }
  22. public List<Command> Commands { get; set; }
  23. public List<Option> Options { get; set; }
  24. public event EventHandler<string> ModuleErrorEvent;
  25. public event Action<Exception> ExceptionThrown;
  26. public bool Loaded { get; set; }
  27. public bool ShouldSerializeLoaded()
  28. {
  29. return false;
  30. }
  31. public string ConfigPath { get; set; }
  32. public bool ShouldSerializeConfigPath()
  33. {
  34. return false;
  35. }
  36. protected Bot Bot;
  37. private ReaderWriterLockSlim ConfigRWLock;
  38. private ReaderWriterLockSlim ConfigFileRWLock;
  39. private JsonSerializerSettings JsonSettings;
  40. public Module()
  41. {
  42. SetDefaults();
  43. ConfigRWLock = new ReaderWriterLockSlim();
  44. ConfigFileRWLock = new ReaderWriterLockSlim();
  45. JsonSettings = new JsonSerializerSettings();
  46. JsonSettings.Converters.Add(new IPAddressConverter());
  47. JsonSettings.Converters.Add(new IPEndPointConverter());
  48. JsonSettings.Formatting = Formatting.Indented;
  49. }
  50. public void HandleCommandEvent(CommandMessage command)
  51. {
  52. try
  53. {
  54. // Check to make sure the command exists, the nick or channel isn't on a blacklist, and the module is loaded.
  55. if (Loaded
  56. && Enabled
  57. && !ChannelBlacklist.Contains(command.Location)
  58. && !NickBlacklist.Contains(command.Nick.Nickname)
  59. && Commands.Exists(c => c.Triggers.Contains(command.Command)
  60. && c.Enabled
  61. && !c.ChannelBlacklist.Contains(command.Location)
  62. && !c.NickBlacklist.Contains(command.Nick.Nickname)
  63. )
  64. )
  65. {
  66. Bot.Log("Checking Command " + command.Command);
  67. // Figure out access of the nick
  68. Command cmd = Commands.Find(c => c.Triggers.Contains(command.Command));
  69. List<AccessType> nickAccessTypes = new List<AccessType>() { AccessType.User };
  70. foreach (PrivilegeMode privilege in command.Nick.Privileges)
  71. {
  72. nickAccessTypes.Add(Bot.PrivilegeModeMapping[privilege]);
  73. }
  74. if ((Bot.ServerConfig.Owners.Contains(command.Nick.Nickname) && command.Nick.Modes.Exists(mode => mode == UserMode.r || mode == UserMode.o)) || command.Nick.Nickname == Bot.IRC.Nickname)
  75. {
  76. nickAccessTypes.Add(AccessType.Owner);
  77. }
  78. command.Access.AddRange(nickAccessTypes);
  79. // If they have the correct access for the command, send it
  80. if (cmd.AllowedAccess.Exists(access => nickAccessTypes.Contains(access)))
  81. {
  82. // Make sure that the command isn't being spammed
  83. if (Bot.SpamCheck(Bot.IRC.Channels.Find(chan => chan.Name == command.Location), command.Nick, this, cmd))
  84. {
  85. ParseCommand(command);
  86. }
  87. }
  88. else
  89. {
  90. string noAccessMessage = string.Format("You do not have access to use \u0002{0}\u000F.", command.Command);
  91. SendResponse(command.MessageType, command.Location, command.Nick.Nickname, noAccessMessage, true);
  92. }
  93. }
  94. }
  95. catch (Exception ex)
  96. {
  97. ThrowException(ex, "Unable to handle module command.");
  98. }
  99. }
  100. virtual public void Initialize() { }
  101. virtual public void ParseCommand(CommandMessage command) { }
  102. protected void ThrowError(string e)
  103. {
  104. string errorMsg = string.Format("[{0}] {1}", Name, e);
  105. EventHandler<string> handler = ModuleErrorEvent;
  106. if (handler != null)
  107. {
  108. handler(this, errorMsg);
  109. }
  110. }
  111. protected void ThrowException(Exception ex)
  112. {
  113. ThrowException(ex, string.Format("Module {0} threw exception.", Name));
  114. }
  115. protected void ThrowException(Exception ex, string message)
  116. {
  117. Exception newEx = new Exception(message, ex);
  118. if (ExceptionThrown != null)
  119. {
  120. ExceptionThrown(newEx);
  121. }
  122. }
  123. public void SetDefaults()
  124. {
  125. Name = string.Empty;
  126. ClassName = string.Empty;
  127. Enabled = false;
  128. ChannelBlacklist = new List<string>();
  129. NickBlacklist = new List<string>();
  130. ConfigPath = Directory.GetCurrentDirectory();
  131. Loaded = false;
  132. Commands = new List<Command>();
  133. Options = new List<Option>();
  134. }
  135. public void Copy(Module module)
  136. {
  137. Name = module.Name;
  138. ClassName = module.ClassName;
  139. Enabled = module.Enabled;
  140. ChannelBlacklist = new List<string>();
  141. foreach (string channel in module.ChannelBlacklist)
  142. {
  143. ChannelBlacklist.Add(channel);
  144. }
  145. NickBlacklist = new List<string>();
  146. foreach (string nick in module.NickBlacklist)
  147. {
  148. NickBlacklist.Add(nick);
  149. }
  150. Commands = new List<Command>();
  151. foreach (Command command in module.Commands)
  152. {
  153. Command newCommand = new Command();
  154. newCommand.Copy(command);
  155. Commands.Add(newCommand);
  156. }
  157. Options = new List<Option>();
  158. foreach (Option option in module.Options)
  159. {
  160. Option newOption = new Option();
  161. newOption.Copy(option);
  162. Options.Add(newOption);
  163. }
  164. }
  165. public Module CreateInstance(Bot bot)
  166. {
  167. Module newModule = new Module();
  168. try
  169. {
  170. if (!Loaded)
  171. {
  172. //create the class base on string
  173. //note : include the namespace and class name (namespace=Combot.Modules, class name=<class_name>)
  174. Assembly a = Assembly.LoadFrom(Path.Combine(ConfigPath, string.Format("{0}.dll", Name)));
  175. Type t = a.GetType("Combot.Modules.Plugins." + ClassName);
  176. //check to see if the class is instantiated or not
  177. if (t != null)
  178. {
  179. newModule = (Module)Activator.CreateInstance(t);
  180. newModule.Copy(this);
  181. newModule.Loaded = true;
  182. newModule.ConfigPath = ConfigPath;
  183. newModule.Bot = bot;
  184. newModule.Initialize();
  185. }
  186. }
  187. }
  188. catch (Exception ex)
  189. {
  190. ThrowException(ex, "Unable to create module instance for " + Name + ".");
  191. }
  192. return newModule;
  193. }
  194. public object GetOptionValue(string name)
  195. {
  196. object foundValue = string.Empty;
  197. Option foundOption = Options.Find(opt => opt.Name == name);
  198. if (foundOption != null)
  199. {
  200. foundValue = foundOption.Value;
  201. if (foundValue == null)
  202. {
  203. foundValue = string.Empty;
  204. }
  205. }
  206. return foundValue;
  207. }
  208. public void SaveConfig()
  209. {
  210. ConfigFileRWLock.EnterWriteLock();
  211. // Serialize Config
  212. ConfigRWLock.EnterReadLock();
  213. string configContents = JsonConvert.SerializeObject(this, JsonSettings);
  214. ConfigRWLock.ExitReadLock();
  215. // Save config to file
  216. string path = Path.Combine(ConfigPath, "Module.json");
  217. using (StreamWriter streamWriter = new StreamWriter(path, false))
  218. {
  219. streamWriter.Write(configContents);
  220. }
  221. ConfigFileRWLock.ExitWriteLock();
  222. }
  223. public void LoadConfig()
  224. {
  225. ConfigFileRWLock.EnterReadLock();
  226. string path = Path.Combine(ConfigPath, "Module.json");
  227. if (!File.Exists(path))
  228. {
  229. string defaultPath = Path.Combine(ConfigPath, "Module.Default.json");
  230. if (File.Exists(defaultPath))
  231. {
  232. File.Copy(defaultPath, path);
  233. }
  234. }
  235. if (File.Exists(path))
  236. {
  237. string configContents;
  238. using (StreamReader streamReader = new StreamReader(path, Encoding.UTF8))
  239. {
  240. configContents = streamReader.ReadToEnd();
  241. }
  242. // Load the deserialized file into the config
  243. ConfigRWLock.EnterWriteLock();
  244. Module newModule = JsonConvert.DeserializeObject<Module>(configContents, JsonSettings);
  245. Copy(newModule);
  246. ConfigRWLock.ExitWriteLock();
  247. }
  248. ConfigFileRWLock.ExitReadLock();
  249. }
  250. public void AddServer()
  251. {
  252. string search = "SELECT * FROM `servers` WHERE " +
  253. "`name` = {0}";
  254. List<Dictionary<string, object>> results = Bot.Database.Query(search, new object[] { Bot.ServerConfig.Name });
  255. if (!results.Any())
  256. {
  257. string query = "INSERT INTO `servers` SET " +
  258. "`name` = {0}";
  259. Bot.Database.Execute(query, new object[] { Bot.ServerConfig.Name });
  260. }
  261. }
  262. public void AddChannel(string channel)
  263. {
  264. string search = "SELECT * FROM `channels` WHERE " +
  265. "`server_id` = (SELECT `id` FROM `servers` WHERE `name` = {0}) AND " +
  266. "`name` = {1}";
  267. List<Dictionary<string, object>> results = Bot.Database.Query(search, new object[] { Bot.ServerConfig.Name, channel });
  268. if (!results.Any())
  269. {
  270. string query = "INSERT INTO `channels` SET " +
  271. "`server_id` = (SELECT `id` FROM `servers` WHERE `name` = {0}), " +
  272. "`name` = {1}";
  273. Bot.Database.Execute(query, new object[] { Bot.ServerConfig.Name, channel });
  274. }
  275. }
  276. public void AddNick(Nick nick)
  277. {
  278. // Let's see if the nick already is added
  279. string search = "SELECT * FROM `nicks` WHERE " +
  280. "`server_id` = (SELECT `id` FROM `servers` WHERE `name` = {0}) AND " +
  281. "`nickname` = {1}";
  282. List<Dictionary<string, object>> results = Bot.Database.Query(search, new object[] { Bot.ServerConfig.Name, nick.Nickname });
  283. if (!results.Any())
  284. {
  285. string insert = "INSERT INTO `nicks` SET " +
  286. "`server_id` = (SELECT `id` FROM `servers` WHERE `name` = {0}), " +
  287. "`nickname` = {1}";
  288. Bot.Database.Execute(insert, new object[] { Bot.ServerConfig.Name, nick.Nickname });
  289. }
  290. // search for the nick's modes (if any)
  291. List<Channel> tmpChannels = new List<Channel>(Bot.IRC.Channels);
  292. foreach (Channel channel in tmpChannels)
  293. {
  294. if (channel.Nicks.Exists(chn => chn.Nickname == nick.Nickname))
  295. {
  296. Nick foundNick = channel.Nicks.Find(chn => chn.Nickname == nick.Nickname);
  297. nick.AddModes(foundNick.Modes);
  298. nick.AddPrivileges(foundNick.Privileges);
  299. }
  300. }
  301. // Now add that nick's info to the db
  302. AddNickInfo(nick);
  303. }
  304. public void AddNickInfo(Nick nickInfo)
  305. {
  306. int argIndex = 2;
  307. string search = "SELECT `nickinfo`.`id` FROM `nickinfo` WHERE " +
  308. "`nick_id` = (SELECT `nicks`.`id` FROM `nicks` INNER JOIN `servers` ON `nicks`.`server_id` = `servers`.`id` WHERE `nicks`.`nickname` = {0} AND `servers`.`name` = {1})";
  309. List<object> argList = new List<object>() { nickInfo.Nickname, Bot.ServerConfig.Name };
  310. if (!string.IsNullOrEmpty(nickInfo.Username))
  311. {
  312. search += " AND `username` = {" + argIndex + "}";
  313. argList.Add(nickInfo.Username);
  314. argIndex++;
  315. }
  316. if (!string.IsNullOrEmpty(nickInfo.Realname))
  317. {
  318. search += " AND `realname` = {" + argIndex + "}";
  319. argList.Add(nickInfo.Realname);
  320. argIndex++;
  321. }
  322. if (!string.IsNullOrEmpty(nickInfo.Host))
  323. {
  324. search += " AND `host` = {" + argIndex + "}";
  325. argList.Add(nickInfo.Host);
  326. }
  327. List<Dictionary<string, object>> results = Bot.Database.Query(search, argList.ToArray());
  328. if (!results.Any())
  329. {
  330. argIndex = 2;
  331. string insert = "INSERT INTO `nickinfo` SET " +
  332. "`nick_id` = (SELECT `nicks`.`id` FROM `nicks` INNER JOIN `servers` ON `nicks`.`server_id` = `servers`.`id` WHERE `nicks`.`nickname` = {0} AND `servers`.`name` = {1})";
  333. argList = new List<object>() { nickInfo.Nickname, Bot.ServerConfig.Name };
  334. if (!string.IsNullOrEmpty(nickInfo.Username))
  335. {
  336. insert += ", `username` = {" + argIndex + "}";
  337. argList.Add(nickInfo.Username);
  338. argIndex++;
  339. }
  340. if (!string.IsNullOrEmpty(nickInfo.Realname))
  341. {
  342. insert += ", `realname` = {" + argIndex + "}";
  343. argList.Add(nickInfo.Realname);
  344. argIndex++;
  345. }
  346. if (!string.IsNullOrEmpty(nickInfo.Host))
  347. {
  348. insert += ", `host` = {" + argIndex + "}";
  349. argList.Add(nickInfo.Host);
  350. argIndex++;
  351. }
  352. if (nickInfo.Modes.Any() && nickInfo.Modes.Contains(UserMode.r))
  353. {
  354. insert += ", `registered` = {" + argIndex + "}";
  355. argList.Add(true);
  356. }
  357. Bot.Database.Execute(insert, argList.ToArray());
  358. }
  359. else
  360. {
  361. string update = "UPDATE `nickinfo` SET `registered` = {0} WHERE `id` = {1}";
  362. Bot.Database.Execute(update, new object[] { (nickInfo.Modes.Any() && nickInfo.Modes.Contains(UserMode.r)), results.First()["id"] });
  363. }
  364. }
  365. public string GetNickname(int id)
  366. {
  367. string search = "SELECT `nickname` FROM `nicks` " +
  368. "WHERE `id` = {0}";
  369. List<Dictionary<string, object>> results = Bot.Database.Query(search, new object[] { id });
  370. string nickname = string.Empty;
  371. if (results.Any())
  372. {
  373. nickname = results.First()["nickname"].ToString();
  374. }
  375. return nickname;
  376. }
  377. public void SendResponse(MessageType messageType, string location, string nickname, string message, bool silent = false)
  378. {
  379. switch (messageType)
  380. {
  381. case MessageType.Channel:
  382. if (silent)
  383. {
  384. Bot.IRC.Command.SendNotice(nickname, message);
  385. }
  386. else
  387. {
  388. Bot.IRC.Command.SendPrivateMessage(location, message);
  389. }
  390. break;
  391. case MessageType.Query:
  392. Bot.IRC.Command.SendPrivateMessage(nickname, message);
  393. break;
  394. case MessageType.Notice:
  395. Bot.IRC.Command.SendNotice(nickname, message);
  396. break;
  397. }
  398. }
  399. }
  400. }