diff --git a/main.py b/main.py index 5c8fdbb..32cae4d 100755 --- a/main.py +++ b/main.py @@ -56,7 +56,7 @@ class log(): class pircbot(): def __init__(self, nicknames, server, port=6667, ident="pircbot", realname="pircbot", serverpasswd="", - encodings=("utf-8", "latin-1"), admins="", + encodings=("utf-8", "latin-1"), users="", query_type="", command_prefix=".", parser_wait_time=0.1): self.server = server @@ -68,7 +68,7 @@ class pircbot(): self.ident = ident self.realname = realname - self.admins = admins + self.users = users self.cmdprefix = command_prefix self.query_type = query_type.upper() @@ -85,7 +85,7 @@ class pircbot(): self.die_event = Event() self.ready = False - self.mode_reply_to = None + self.mode_reply = {} def connect(self): # connect @@ -178,7 +178,6 @@ class pircbot(): # parse params params = head params.append(larg.strip()) - print(params) log.show(log.DEBUG, " > %s" % rawline) @@ -187,22 +186,23 @@ class pircbot(): self.send("PONG %s" % params[0]) # PRIVMSG and NOTICE elif command == "PRIVMSG" or command == "NOTICE": - if params[1].startswith(self.cmdprefix): + if params[1][0] == self.cmdprefix: args = [] - for v in params[1].lstrip(self.cmdprefix).split(" "): + for v in params[1][1:].split(" "): if v!="": args.append(v) - sndline = self.on_command(command, prefix, origin, params[0], args[0].lower(), args[1:]) - if sndline != None: - self.send(sndline) + rp = self.on_command(command, prefix, origin, params[0], args[0].lower(), args[1:]) + if rp not in (None, ""): + self.reply(origin, params[0], rp, command) # 221 (RPL_UMODEIS) - elif command == "221" and self.mode_reply_to is not None: - self.send("PRIVMSG %s :Modes are %s" % (self.mode_reply_to, params[1])) + elif command == "221" and self.mode_reply is not {}: + self.query(self.mode_reply["to"], "Modes are %s" % params[1], self.mode_reply["type"]) + self.mode_reply = {} # INVITE elif command == "INVITE": - if self.is_admin(origin["mask"]): + if self.check_privileges(origin["mask"], command): self.join(params[1]) else: - self.send("NOTICE %s :You can not force me to do that!" % origin["nick"]) + self.query(origin["nick"], "You can not force me to do that!", "NOTICE") # 001 (RPL_WELCOME) elif command == "001": self.user["mask"] = re.search(r" (\S+!\S+@\S+)$", rawline.split(" :", 1)[1]).groups()[0] @@ -237,16 +237,18 @@ class pircbot(): return textstring.decode(self.encodings[0], 'ignore') - # checks if a given user is listed in admins - def is_admin(self, user): - for admin in self.admins: - if re.search(admin, user) != None: - return True + # checks if a given user may execute a given command + def check_privileges(self, usermask, command): + for user, privs in self.users.items(): + if re.search(user, usermask, re.IGNORECASE) != None: + if command.lower() in privs or "*" in privs: + return True return False + # checks if s is a valid channel name def is_channel(self, s): - return (True if s[0] in ('&', '#', '+', '!') else False) + return (True if s[0] in ('&', '#', '!') else False) def exec_on_ready(self, command, retry_times=-1, interval=1): @@ -281,15 +283,7 @@ class pircbot(): log.show(log.FATAL, e) self.disconnect(send_quit=False) - # replies to channel by PRIVMSG - def chanmsg(self, channel, msg): - self.send("".join(("PRIVMSG ", channel, " :", msg))) - - # replies to user by NOTICE or PRIVMSG - def query(self, nick, msg, in_query_type): - self.send("".join((self.query_type if self.query_type!="" else in_query_type, " ", nick, " :", msg))) - - # decides whether to print to user or to channel based on the string origin + # decides whether to reply to user or to channel def reply(self, origin, source, msg, in_query_type): if self.is_channel(source): self.chanmsg(source, msg) @@ -299,6 +293,14 @@ class pircbot(): ### irc command wrapper ### + # replies to channel by PRIVMSG + def chanmsg(self, channel, msg): + self.send("".join(("PRIVMSG ", channel, " :", msg))) + + # replies to user by NOTICE or PRIVMSG + def query(self, nick, msg, in_query_type): + self.send("".join((self.query_type if self.query_type!="" else in_query_type, " ", nick, " :", msg))) + def nick(self, nick): self.exec_on_ready("".join(('self.send("JOIN %s" % "', channel, '")'))) @@ -308,11 +310,11 @@ class pircbot(): def part(self, channel): self.exec_on_ready("".join(('self.send("PART %s" % "', channel, '")'))) - def set_mode(self, modes): - self.exec_on_ready("".join(('self.send("MODE %s :%s" % (self.user["nick"], "', modes, '"))'))) + def set_mode(self, modes, target=""): + self.exec_on_ready("".join(('self.send("MODE %s :%s" % (', ''.join(('"', target, '"')) if target != "" else 'self.user["nick"]', ', "', modes, '"))'))) - def get_modes(self): - self.exec_on_ready("".join(('self.send("MODE %s" % self.user["nick"])'))) + def get_modes(self, target=""): + self.exec_on_ready("".join(('self.send("MODE %s" % ', ''.join(('"', target, '"')) if target != "" else 'self.user["nick"]', ')'))) ### handler ### @@ -331,36 +333,42 @@ class pircbot(): # hello if command == "hello": greeting = "".join(("Hi " + origin["nick"] +"!")) - self.reply(origin, source, greeting, in_query_type) + return greeting + # say + if command == "say": + return " ".join(params) # join - elif command == "join" and len(params)>0: - if self.is_admin(origin["mask"]): self.join(params[0]) - else: return "PRIVMSG %s :You cannot do that!" % origin["nick"] + elif command == "join": + if len(params)>0: + if self.check_privileges(origin["mask"], command): self.join(params[0]) + else: self.query(origin["nick"], "You cannot do that!", in_query_type) # part - elif command == "part" and len(params)>0: - if self.is_admin(origin["mask"]): self.part(params[0]) - else: return "PRIVMSG %s :You cannot do that!" % origin["nick"] + elif command == "part": + if len(params)>0: + if self.check_privileges(origin["mask"], command): self.part(params[0]) + else: self.query(origin["nick"], "You cannot do that!", in_query_type) # mode ± elif command == "mode": - if self.is_admin(origin["mask"]): - if len(params) > 0: - self.set_mode(params[0]) - else: - self.mode_reply_to = origin["nick"] + if self.check_privileges(origin["mask"], command): + if len(params)==0: + self.mode_reply["to"] = origin["nick"] + self.mode_reply["type"] = in_query_type self.get_modes() - else: return "PRIVMSG %s :You cannot do that!" % origin["nick"] + else: + self.set_mode(" ".join(params) if len(params)>0 else params) + else: self.query(origin["nick"], "You cannot do that!", in_query_type) # die [] elif command == "die": - if self.is_admin(origin["mask"]): + if self.check_privileges(origin["mask"], command): self.disconnect("".join(params) if len(params)>0 else "".join((origin["nick"], " shot me, dying now... Bye..."))) - else: return "PRIVMSG %s :Go die yourself!" % origin["nick"] + else: self.query(origin["nick"], "Go die yourself!", in_query_type) else: replies = [ - ("PRIVMSG %s :What? \"%s\" is not a command!", 15), - ("PRIVMSG %s :%s? What's that?", 3), - ("PRIVMSG %s :Sorry, I don't know how to %s...", 1) + ("What? \"%s\" is not a command!", 15), + ("%s? What's that?", 3), + ("Sorry, I don't know how to %s...", 1) ] - return choice([val for val, cnt in replies for i in range(cnt)]) % (origin["nick"], command) + self.query(origin["nick"], choice([val for val, cnt in replies for i in range(cnt)]) % (command), in_query_type) @@ -379,7 +387,7 @@ def main(): try: bot = pircbot(nicknames=NICKNAMES, ident=IDENT, realname=REALNAME, server=SERVER, port=PORT, serverpasswd=SERVERPASSWD, - encodings=ENCODINGS, admins=ADMINS, + encodings=ENCODINGS, users=USERS, query_type=QUERY_TYPE, command_prefix=COMMAND_PREFIX, parser_wait_time=PARSER_WAIT_TIME) bot.connect() @@ -425,7 +433,7 @@ if __name__ == '__main__': # Command for registering with nickserv, without leading slash. NICKSERVCMD = "" - MODES = "+B" + MODES = "+iB" # The Server name to connect to. Duh! @@ -449,15 +457,19 @@ if __name__ == '__main__': ENCODINGS = ['utf-8', 'latin-1', 'iso-8859-1', 'cp1252'] - # List of users (hostmasks, will be parsed as regex) who can do important stuff, - # like joining and parting channels and shutting down the bot. - ADMINS = ["Fanir\!.*"] + # List of users (hostmasks as regex) and the commands they are allowed to execute. + # "*" Can be used instead of commands to allow every command. + # All command names should be lowercase. + USERS = { + "Fanir\!fanir@.*": ["*"], + "\!@some weird user that cannot exist": ["join", "part", "invite"], + } # The prefix for commands for the bot. COMMAND_PREFIX = "." - # Which way shouldbe used to speak to users? - # "" means, the type of the incomming message should be used. + # Which way should be used to speak to users? + # "" means the type of the incoming message should be used. # One of: "NOTICE", "PRIVMSG", "" QUERY_TYPE = ""