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

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