diff --git a/irc.py b/irc.py index 8c170ce0fb9b7a312d6b0e0d65878ffec6870624..abd701a66b76c34c78035d99147f8b165e74734a 100644 --- a/irc.py +++ b/irc.py @@ -1,6 +1,12 @@ import socket, os, threading, re import plugins +class User(str): + def __init__(self, nick): + super(User, self).__init__(self, nick) + self.ident = "" + self.host = "" + class PluginManager(object): def __init__(self, server): self.server = server @@ -49,10 +55,8 @@ class PluginManager(object): def event(self, eventName, *args): eventName = eventName.lower() if eventName == "command": - handler = None - try: - handler = self.handlers[eventName][args[2].lower()] - except KeyError,ke: + handler = self.handlers[eventName].get(args[2].lower(), None) + if handler is None: return #no such command try: @@ -208,7 +212,7 @@ class IRC(threading.Thread): self.goodstart = False if self.goodstart: - ident = self.config["ident"] if self.config["ident"] != "" else self.config["nickname"] + self.config["ident"] = ident = self.config["ident"] if self.config["ident"] != "" else self.config["nickname"] self.sendLine("USER "+ident+" * * *") self.sendLine("NICK "+self.config["nickname"]) @@ -247,13 +251,12 @@ class IRC(threading.Thread): # Takes the ':Nick!Ident@Host' chunk and assigns (nick,ident,host) to user user = None if words[0].find("!") != -1: - nick = words[0][words[0].find(":") + 1:words[0].find('!')] - ident = words[0][words[0].find('!') + 1:words[0].find('@')] - host = words[0][words[0].find('@') + 1:] - user = (nick,ident,host) + user = User(words[0][words[0].find(":") + 1:words[0].find('!')]) + user.ident = words[0][words[0].find('!') + 1:words[0].find('@')] + user.host = words[0][words[0].find('@') + 1:] else: - nick = words[0][words[0].find(":") + 1:] - user = (nick, "", "") + #it's our nick, in the format ":NickName" + user = User(words[0][words[0].find(":") + 1:]) if words[1] == "433": #There was a nick collision @@ -281,7 +284,7 @@ class IRC(threading.Thread): elif words[1] == "PRIVMSG": # We got a message - channel = (words[2] if words[2] != self.config["nickname"] else user[0]) + channel = (words[2] if words[2] != self.config["nickname"] else user) message = data[data.find(":", data.find(channel[(channel.find("-") == -1 and 1 or channel.find("-")):]))+1:] if message.find("\x01ACTION") == 0: # String was found, it's an action @@ -307,29 +310,29 @@ class IRC(threading.Thread): elif words[1] == "JOIN": # Someone joined a channel that we're in - if user[0] != self.config["nickname"]: + if user != self.config["nickname"]: self.pluginManager.event("join", words[2].strip(":"), user) - self.userlist[words[2].strip(":")].append(user[0]) + self.userlist[words[2].strip(":")].append(user) elif words[1] == "PART": - if user[0] != self.config["nickname"]: + if user != self.config["nickname"]: # Someone parted a channel we're in - if user[0] in self.userlist[words[2].strip(":")]: - self.userlist[words[2]].remove(user[0]) - self.pluginManager.event("part", words[2].strip(":"), user[0], " ".join(words[3:])) + if user in self.userlist[words[2].strip(":")]: + self.userlist[words[2]].remove(user) + self.pluginManager.event("part", words[2].strip(":"), user, " ".join(words[3:])) elif words[1] == "QUIT": # Someone quit the server for k in self.userlist.keys(): - if user[0] in self.userlist[k]: - self.userlist[k].remove(user[0]) + if user in self.userlist[k]: + self.userlist[k].remove(user) self.pluginManager.event("quit", user, " ".join(words[2:])[1:]) elif words[1] == "NICK": # Someone changed their nickname for k in self.userlist.keys(): - if user[0] in self.userlist[k]: - self.userlist[k].remove(user[0]) + if user in self.userlist[k]: + self.userlist[k].remove(user) self.userlist[k].append(words[2].strip(":")) self.pluginManager.event("nick", user, words[2].strip(":")) @@ -363,15 +366,15 @@ class IRC(threading.Thread): def doMessage(self, channel, message): self.sendLine("PRIVMSG "+channel+" :"+message) - self.pluginManager.event("message", channel, (self.config["nickname"],"",""), message) + self.pluginManager.event("message", channel, User(self.config["nickname"]), message) def doAction(self, channel, action): self.sendLine("PRIVMSG "+channel+" :\x01ACTION "+action+" \x01") - self.pluginManager.event("action", channel, (self.config["nickname"],"",""), action) + self.pluginManager.event("action", channel, User(self.config["nickname"]), action) def doQuit(self, message=""): self.sendLine("QUIT :" + message) - self.pluginManager.event("quit", (self.config["nickname"],"",""), message) + self.pluginManager.event("quit", User(self.config["nickname"]), message) self.running = False def doNotice(self, user, message): @@ -379,23 +382,23 @@ class IRC(threading.Thread): def doNick(self, newnick): self.sendLine("NICK " + newnick) - self.pluginManager.event("nick", self.config["nickname"], (newnick,"","")) + self.pluginManager.event("nick", User(self.config["nickname"]), User(newnick)) self.config["nickname"] = newnick def doJoin(self, channel): self.sendLine("JOIN "+channel) - self.pluginManager.event("join", channel, (self.config["nickname"],"","")) + self.pluginManager.event("join", channel, User(self.config["nickname"])) def doKick(self, channel, user, message=""): self.sendLine("KICK %s %s :%s" % (channel, user, message)) - self.pluginManager.event("kick", channel, (self.config["nickname"],"",""), user, message) + self.pluginManager.event("kick", channel, User(self.config["nickname"]), user, message) def doPart(self, channel, message=""): self.sendLine("PART "+channel) if channel in self.userlist.keys(): del self.userlist[channel] - self.pluginManager.event("part", channel, (self.config["nickname"],"",""), message) + self.pluginManager.event("part", channel, User(self.config["nickname"]), message) def doMode(self, channel, mode, user=""): self.sendLine("MODE "+channel+" "+mode+user) - self.pluginManager.event("mode", channel, (self.config["nickname"],"",""), mode, user) + self.pluginManager.event("mode", channel, User(self.config["nickname"]), mode, user) diff --git a/plugins/auth.py b/plugins/auth.py index cc1467ec8cb9d0003dcd03ff24c0c67f629a145c..8bb45a654b81f6de5049f87d44db9f3600f5849e 100644 --- a/plugins/auth.py +++ b/plugins/auth.py @@ -53,7 +53,6 @@ class Auth(object): del self.mods[oldnick.lower()] def handle_command(self, channel, user, cmd, args): - user = user[0] if cmd == "owners": self.server.doMessage(channel, user+": My owners are: "+" ".join(self.owners)) elif cmd == "admins": diff --git a/plugins/bbot.py b/plugins/bbot.py new file mode 100644 index 0000000000000000000000000000000000000000..394c166a1b151e253d292e789fafe60c3a950212 --- /dev/null +++ b/plugins/bbot.py @@ -0,0 +1,75 @@ +import re +import time + +@plugin +class Blockbot(object): + def __init__(self, server): + self.server = server + self.prnt = server.prnt + + self.server.handle("message", self.handle_message) + + findlist = [ + 'you will be unable to connect to freenode unless you are using sasl' + ] + self.mps_limit = 4 + self.storage_time = 25 + self.repeat_limit = 3 + self.repeat_1word = 4 + + # Compile Spam Strings + self.findlist = [] + if findlist: + for each in findlist: + self.findlist.append(re.compile(each)) + + # Load Default Data + self.msglist = [] + #self.lastnot = ('BBot', time.time(), 'sdkljfls') + + def handle_message(self, channel, nick, message): + """ Called when a message is received """ + self.msglist.insert(0, (nick, channel, message, + time.time())) + + # Check for spam strings + ldata = message.lower() + for each in self.findlist: + if re.search(each, ldata): + self.server.doKick(channel, nick, 'You have matched a spam string and have been banned, if you this is a mistake, contact a channel op to be unbanned') + return + + # Extract messages by this user + user_msgs = [] + for msg in self.msglist: + if msg[0] == nick: + user_msgs.append((nick, msg[1], msg[2], msg[3])) + + # Check for flooding + if self.get_mps(user_msgs) > self.mps_limit: + self.server.doKick(channel, nick,'Please do not flood') + self.msglist.pop(0) + + # Check for repeats + strings = [] + repeats = 0 + for msg in user_msgs: + if msg[2] not in strings: + strings.append(msg[2]) + else: + repeats += 1 + if repeats > self.repeat_limit-1: + self.server.doKick(channel, nick, 'Do not repeat yourself...') + self.msglist.pop(0) + + # Clear out old messages + now = time.time() + for msg in self.msglist: + if now - msg[3] > self.storage_time: + self.msglist.remove(msg) + + def get_mps(self, user_msgs): + '''Count the number of messages sent per second''' + time_range = user_msgs[0][3] - user_msgs[-1][3] + mps = len(user_msgs) / time_range + return mps diff --git a/plugins/blockbot.py b/plugins/blockbot.py new file mode 100644 index 0000000000000000000000000000000000000000..394c166a1b151e253d292e789fafe60c3a950212 --- /dev/null +++ b/plugins/blockbot.py @@ -0,0 +1,75 @@ +import re +import time + +@plugin +class Blockbot(object): + def __init__(self, server): + self.server = server + self.prnt = server.prnt + + self.server.handle("message", self.handle_message) + + findlist = [ + 'you will be unable to connect to freenode unless you are using sasl' + ] + self.mps_limit = 4 + self.storage_time = 25 + self.repeat_limit = 3 + self.repeat_1word = 4 + + # Compile Spam Strings + self.findlist = [] + if findlist: + for each in findlist: + self.findlist.append(re.compile(each)) + + # Load Default Data + self.msglist = [] + #self.lastnot = ('BBot', time.time(), 'sdkljfls') + + def handle_message(self, channel, nick, message): + """ Called when a message is received """ + self.msglist.insert(0, (nick, channel, message, + time.time())) + + # Check for spam strings + ldata = message.lower() + for each in self.findlist: + if re.search(each, ldata): + self.server.doKick(channel, nick, 'You have matched a spam string and have been banned, if you this is a mistake, contact a channel op to be unbanned') + return + + # Extract messages by this user + user_msgs = [] + for msg in self.msglist: + if msg[0] == nick: + user_msgs.append((nick, msg[1], msg[2], msg[3])) + + # Check for flooding + if self.get_mps(user_msgs) > self.mps_limit: + self.server.doKick(channel, nick,'Please do not flood') + self.msglist.pop(0) + + # Check for repeats + strings = [] + repeats = 0 + for msg in user_msgs: + if msg[2] not in strings: + strings.append(msg[2]) + else: + repeats += 1 + if repeats > self.repeat_limit-1: + self.server.doKick(channel, nick, 'Do not repeat yourself...') + self.msglist.pop(0) + + # Clear out old messages + now = time.time() + for msg in self.msglist: + if now - msg[3] > self.storage_time: + self.msglist.remove(msg) + + def get_mps(self, user_msgs): + '''Count the number of messages sent per second''' + time_range = user_msgs[0][3] - user_msgs[-1][3] + mps = len(user_msgs) / time_range + return mps diff --git a/plugins/info.py b/plugins/info.py index ab40a30098070cf2424c360e5462c81d8a3bf928..2dafe567b2c68b0e03bef8f85d7c04341dc8f1ec 100644 --- a/plugins/info.py +++ b/plugins/info.py @@ -32,7 +32,6 @@ class Info(object): return [None, None] def handle_command(self, channel, user, cmd, args, info_silent = False): - user = user[0] if cmd == "what" or cmd == "who": for i in range(0, len(args)): args[i] = self.badchars.sub("", args[i]) diff --git a/plugins/plugintools.py b/plugins/plugintools.py index 5a2ae340e0732e1088097063ba7d8fc2a0579f01..9a744bbb8744d145a5a594f5f689e08076fd0c63 100644 --- a/plugins/plugintools.py +++ b/plugins/plugintools.py @@ -9,7 +9,6 @@ class PluginLoader(object): self.server.handle("command", self.handle_command, self.commands) def handle_command(self, channel, user, cmd, args): - user = user[0] if self.server.getPlugin("auth").isMod(user): if cmd == "reloadall": self.server.pluginManager.unloadAllPlugins() diff --git a/plugins/printer.py b/plugins/printer.py index 7a8456610c315ef719d53bcf16ca0e23b01c3eb3..2647c660e410a6410ac695ba5636c9228b860002 100644 --- a/plugins/printer.py +++ b/plugins/printer.py @@ -18,11 +18,9 @@ class Printer(object): self.prnt("I have disconnected from %s" % server) def handle_message(self, channel, user, message): - user = user[0] self.prnt("<%s> %s: %s" % (channel, user, message)) def handle_action(self, channel, user, action): - user = user[0] self.prnt("<%s> * %s %s" % (channel, user, action)) def handle_join(self, channel, user): @@ -30,17 +28,16 @@ class Printer(object): self.prnt("%s has joined %s" % (user, channel)) def handle_part(self, channel, user, message): - user = user[0] self.prnt("%s has left %s (%s)" % (user, channel, message)) def handle_quit(self, user, message): - user = user[0] self.prnt("%s has quit (%s)" % (user, message)) def handle_nick(self, oldnick, newnick): - user = user[0] self.prnt("%s is now known as %s" % (oldnick, newnick)) + def handle_kick(self, channel, user, userkicked, message): + self.prnt("%s has kicked %s from %s (%s)" % (user, userkicked, channel, message)) + def handle_mode(self, channel, user, mode, otheruser): - user = user[0] self.prnt("%s set mode %s on %s" % (user, mode, otheruser if otheruser != "" else channel))