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.

Spam_Control.cs 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Threading;
  5. using Combot.IRCServices;
  6. using Combot.IRCServices.Messaging;
  7. namespace Combot.Modules.Plugins
  8. {
  9. public class Spam_Control : Module
  10. {
  11. private List<SpamMessageInfo> SpamMessageList;
  12. private List<SpamHighlightInfo> SpamHighlightList;
  13. private ReaderWriterLockSlim SpamMessageLock;
  14. private ReaderWriterLockSlim SpamHighlightLock;
  15. private List<System.Timers.Timer> unbanTimers;
  16. private ReaderWriterLockSlim unbanLock;
  17. private List<System.Timers.Timer> devoiceTimers;
  18. private ReaderWriterLockSlim devoiceLock;
  19. public override void Initialize()
  20. {
  21. unbanTimers = new List<System.Timers.Timer>();
  22. unbanLock = new ReaderWriterLockSlim();
  23. devoiceTimers = new List<System.Timers.Timer>();
  24. devoiceLock = new ReaderWriterLockSlim();
  25. SpamMessageList = new List<SpamMessageInfo>();
  26. SpamHighlightList = new List<SpamHighlightInfo>();
  27. SpamMessageLock = new ReaderWriterLockSlim();
  28. SpamHighlightLock = new ReaderWriterLockSlim();
  29. Bot.IRC.Message.ChannelMessageReceivedEvent += HandleChannelMessage;
  30. }
  31. private void HandleChannelMessage(object sender, ChannelMessage message)
  32. {
  33. if (Enabled && !ChannelBlacklist.Contains(message.Channel) && !NickBlacklist.Contains(message.Sender.Nickname))
  34. {
  35. CheckFlood(message);
  36. CheckHighlight(message);
  37. }
  38. }
  39. private void CheckFlood(ChannelMessage message)
  40. {
  41. int timeThreshold = Convert.ToInt32(GetOptionValue("Time Threshold"));
  42. int maxMessages = Convert.ToInt32(GetOptionValue("Max Messages"));
  43. int devoiceTime = Convert.ToInt32(GetOptionValue("Devoice Time"));
  44. int unbanTime = Convert.ToInt32(GetOptionValue("Unban Time"));
  45. bool voiceResponse = Convert.ToBoolean(GetOptionValue("Voice Response"));
  46. bool kickResponse = Convert.ToBoolean(GetOptionValue("Kick Response"));
  47. bool banResponse = Convert.ToBoolean(GetOptionValue("Ban Response"));
  48. bool unbanResponse = Convert.ToBoolean(GetOptionValue("Unban Response"));
  49. // Check for line spam
  50. if (SpamMessageList.Exists(msg => msg.Channel == message.Channel && msg.Nick == message.Sender.Nickname))
  51. {
  52. SpamMessageLock.EnterReadLock();
  53. SpamMessageInfo info = SpamMessageList.Find(msg => msg.Channel == message.Channel && msg.Nick == message.Sender.Nickname);
  54. SpamMessageLock.ExitReadLock();
  55. TimeSpan difference = message.TimeStamp.Subtract(info.FirstMessageTime);
  56. if (difference.TotalMilliseconds < timeThreshold)
  57. {
  58. info.Lines++;
  59. if (info.Lines > maxMessages)
  60. {
  61. if (voiceResponse)
  62. {
  63. TimedDeVoice(message, devoiceTime);
  64. }
  65. if (kickResponse)
  66. {
  67. Bot.IRC.Command.SendKick(info.Channel, info.Nick, string.Format("Please do not spam. You have messaged {0} times within {1}ms.", info.Lines, timeThreshold));
  68. }
  69. if (banResponse)
  70. {
  71. if (unbanResponse)
  72. {
  73. TimedBan(message, unbanTime);
  74. }
  75. else
  76. {
  77. BanNick(true, message);
  78. }
  79. }
  80. if (!kickResponse)
  81. {
  82. string spamMessage = string.Format("Please do not spam. You have messaged {0} times within {1}ms.", info.Lines, timeThreshold);
  83. SendResponse(MessageType.Channel, message.Channel, message.Sender.Nickname, spamMessage);
  84. }
  85. SpamMessageLock.EnterWriteLock();
  86. SpamMessageList.Remove(info);
  87. SpamMessageLock.ExitWriteLock();
  88. }
  89. }
  90. else
  91. {
  92. SpamMessageLock.EnterWriteLock();
  93. info.Lines = 1;
  94. info.FirstMessageTime = message.TimeStamp;
  95. SpamMessageLock.ExitWriteLock();
  96. }
  97. }
  98. else
  99. {
  100. SpamMessageInfo info = new SpamMessageInfo();
  101. info.Channel = message.Channel;
  102. info.Nick = message.Sender.Nickname;
  103. info.Lines = 1;
  104. info.FirstMessageTime = message.TimeStamp;
  105. SpamMessageLock.EnterWriteLock();
  106. SpamMessageList.Add(info);
  107. SpamMessageLock.ExitWriteLock();
  108. }
  109. }
  110. private void CheckHighlight(ChannelMessage message)
  111. {
  112. int timeThreshold = Convert.ToInt32(GetOptionValue("Time Threshold"));
  113. int maxHighlights = Convert.ToInt32(GetOptionValue("Max Highlights"));
  114. int devoiceTime = Convert.ToInt32(GetOptionValue("Devoice Time"));
  115. int unbanTime = Convert.ToInt32(GetOptionValue("Unban Time"));
  116. bool voiceResponse = Convert.ToBoolean(GetOptionValue("Voice Response"));
  117. bool kickResponse = Convert.ToBoolean(GetOptionValue("Kick Response"));
  118. bool banResponse = Convert.ToBoolean(GetOptionValue("Ban Response"));
  119. bool unbanResponse = Convert.ToBoolean(GetOptionValue("Unban Response"));
  120. // Check for highlight spam
  121. List<string> splitMessage = message.Message.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToList();
  122. Channel channel = Bot.IRC.Channels.Find(chan => chan.Name == message.Channel);
  123. if (channel != null)
  124. {
  125. List<string> foundNicks = splitMessage.FindAll(msg => channel.Nicks.Exists(nick => msg.Equals(nick.Nickname, StringComparison.InvariantCultureIgnoreCase)));
  126. if (foundNicks.Any())
  127. {
  128. if (!SpamHighlightList.Exists(msg => msg.Channel == message.Channel && msg.Nick == message.Sender.Nickname))
  129. {
  130. SpamHighlightInfo newInfo = new SpamHighlightInfo();
  131. newInfo.Channel = message.Channel;
  132. newInfo.Nick = message.Sender.Nickname;
  133. newInfo.Highlights = 0;
  134. newInfo.FirstHighlightTime = message.TimeStamp;
  135. SpamHighlightLock.EnterWriteLock();
  136. SpamHighlightList.Add(newInfo);
  137. SpamHighlightLock.ExitWriteLock();
  138. }
  139. SpamHighlightLock.EnterReadLock();
  140. SpamHighlightInfo info = SpamHighlightList.Find(highlight => highlight.Channel == message.Channel && highlight.Nick == message.Sender.Nickname);
  141. SpamHighlightLock.ExitReadLock();
  142. TimeSpan difference = message.TimeStamp.Subtract(info.FirstHighlightTime);
  143. if (difference.TotalMilliseconds < timeThreshold)
  144. {
  145. info.Highlights += foundNicks.Count;
  146. if (info.Highlights > maxHighlights)
  147. {
  148. if (voiceResponse)
  149. {
  150. TimedDeVoice(message, devoiceTime);
  151. }
  152. if (kickResponse)
  153. {
  154. Bot.IRC.Command.SendKick(info.Channel, info.Nick, string.Format("Please do not highlight spam. You have highlighted {0} nicks within {1}ms.", info.Highlights, timeThreshold));
  155. }
  156. if (banResponse)
  157. {
  158. if (unbanResponse)
  159. {
  160. TimedBan(message, unbanTime);
  161. }
  162. else
  163. {
  164. BanNick(true, message);
  165. }
  166. }
  167. if (!kickResponse)
  168. {
  169. string spamMessage = string.Format("Please do not highlight spam. You have highlighted {0} nicks within {1}ms.", info.Highlights, timeThreshold);
  170. SendResponse(MessageType.Channel, message.Channel, message.Sender.Nickname, spamMessage);
  171. }
  172. SpamHighlightLock.EnterWriteLock();
  173. SpamHighlightList.Remove(info);
  174. SpamHighlightLock.ExitWriteLock();
  175. }
  176. }
  177. else
  178. {
  179. SpamHighlightLock.EnterWriteLock();
  180. info.Highlights = foundNicks.Count;
  181. info.FirstHighlightTime = message.TimeStamp;
  182. SpamHighlightLock.ExitWriteLock();
  183. }
  184. }
  185. }
  186. }
  187. private void TimedDeVoice(ChannelMessage message, int timeout)
  188. {
  189. SetMode(false, message.Channel, ChannelMode.v, message.Sender.Nickname);
  190. System.Timers.Timer devoiceTrigger = new System.Timers.Timer();
  191. devoiceTrigger.Interval = (timeout * 1000.0);
  192. devoiceTrigger.Enabled = true;
  193. devoiceTrigger.AutoReset = false;
  194. devoiceTrigger.Elapsed += (sender, e) => TimedVoice(sender, e, message);
  195. devoiceLock.EnterWriteLock();
  196. devoiceTimers.Add(devoiceTrigger);
  197. devoiceLock.ExitWriteLock();
  198. }
  199. private void TimedVoice(object sender, EventArgs e, ChannelMessage message)
  200. {
  201. System.Timers.Timer devoiceTimer = (System.Timers.Timer)sender;
  202. devoiceTimer.Enabled = false;
  203. SetMode(true, message.Channel, ChannelMode.v, message.Sender.Nickname);
  204. devoiceLock.EnterWriteLock();
  205. devoiceTimers.Remove(devoiceTimer);
  206. devoiceLock.ExitWriteLock();
  207. }
  208. private void TimedBan(ChannelMessage message, int timeout)
  209. {
  210. BanNick(true, message);
  211. System.Timers.Timer unban_trigger = new System.Timers.Timer();
  212. unban_trigger.Interval = (timeout * 1000.0);
  213. unban_trigger.Enabled = true;
  214. unban_trigger.AutoReset = false;
  215. unban_trigger.Elapsed += (sender, e) => TimedUnBan(sender, e, message);
  216. unbanLock.EnterWriteLock();
  217. unbanTimers.Add(unban_trigger);
  218. unbanLock.ExitWriteLock();
  219. }
  220. private void TimedUnBan(object sender, EventArgs e, ChannelMessage message)
  221. {
  222. System.Timers.Timer unbanTimer = (System.Timers.Timer)sender;
  223. unbanTimer.Enabled = false;
  224. BanNick(false, message);
  225. unbanLock.EnterWriteLock();
  226. unbanTimers.Remove(unbanTimer);
  227. unbanLock.ExitWriteLock();
  228. }
  229. private void BanNick(bool set, ChannelMessage message)
  230. {
  231. string banMask = message.Sender.Nickname;
  232. if (!banMask.Contains("@") || !banMask.Contains("!"))
  233. {
  234. string search = "SELECT `nickinfo`.`username`, `nickinfo`.`host`, `nicks`.`nickname` FROM `nickinfo` " +
  235. "INNER JOIN `nicks` " +
  236. "ON `nickinfo`.`nick_id` = `nicks`.`id` " +
  237. "INNER JOIN `servers` " +
  238. "ON `nicks`.`server_id` = `servers`.`id` " +
  239. "WHERE `servers`.`name` = {0} AND `nicks`.`nickname` = {1}";
  240. List<Dictionary<string, object>> results = Bot.Database.Query(search, new object[] {Bot.ServerConfig.Name, banMask});
  241. if (results.Any())
  242. {
  243. List<string> banMasks = new List<string>();
  244. foreach (Dictionary<string, object> result in results)
  245. {
  246. var nickname = result["nickname"].ToString();
  247. var host = result["host"].ToString();
  248. var username = result["username"].ToString();
  249. if (!string.IsNullOrEmpty(host) && !string.IsNullOrEmpty(username))
  250. {
  251. banMask = string.Format("*!*{0}@{1}", username, host);
  252. }
  253. else if (!string.IsNullOrEmpty(host))
  254. {
  255. banMask = string.Format("*!*@{0}", host);
  256. }
  257. else if (!string.IsNullOrEmpty(username))
  258. {
  259. banMask = string.Format("{0}!*{1}@*", nickname, username);
  260. }
  261. else
  262. {
  263. banMask = string.Format("{0}!*@*", nickname);
  264. }
  265. banMasks.Add(banMask);
  266. }
  267. SetMode(set, message.Channel, ChannelMode.b, banMasks);
  268. }
  269. else
  270. {
  271. SetMode(set, message.Channel, ChannelMode.b, string.Format("{0}!*@*", banMask));
  272. }
  273. }
  274. }
  275. private void SetMode(bool set, string channel, ChannelMode mode, string nickname)
  276. {
  277. ChannelModeInfo modeInfo = new ChannelModeInfo();
  278. modeInfo.Mode = mode;
  279. modeInfo.Parameter = nickname;
  280. modeInfo.Set = set;
  281. Bot.IRC.Command.SendMode(channel, modeInfo);
  282. }
  283. private void SetMode(bool set, string channel, ChannelMode mode, List<string> nicknames)
  284. {
  285. List<ChannelModeInfo> modeInfos = new List<ChannelModeInfo>();
  286. foreach (var nickname in nicknames)
  287. {
  288. ChannelModeInfo modeInfo = new ChannelModeInfo();
  289. modeInfo.Mode = mode;
  290. modeInfo.Parameter = nickname;
  291. modeInfo.Set = set;
  292. modeInfos.Add(modeInfo);
  293. }
  294. Bot.IRC.Command.SendMode(channel, modeInfos);
  295. }
  296. }
  297. }