import string, re from common import userstatus, do_everything_to, log, font, queries from commands.common import CommandHelpers as CH from commands.common import AdminHelpers as AH def do_command(self, connection, event, user, channel): cmdtype, trigger, command, replyto = CH.disect_command(self, event) # Do nothing if it's not a type of command. if not cmdtype: return # Do nothing if there is no command. if not command: return # The first word of the command sting with arguments, is just the command without arguments. try: one = command.split()[0] # Get raw command. except: return # Secret command to let the bot give you channel status. ANd a HUGE security issue ;) if trigger.split()[0] == "!uXVETIkWIL~qG5CasftKKAL 2: # More then one argument. connection.privmsg(replyto, 'Too many arguments, specify one channel only. Example: %s%s%s %s' % (font.blue, self.network.command_character, one, self.network.home_channel)) elif command == 'cmd' or command == 'cmds' or command == 'commands': if cmdtype == "cmd": message = font.grey + "Admin: " if CH.ccc(self, "settings", {"homechan": "oper", "chan": "oper"}, event): message += CH.ccc(self, "settings", {"homechan": "oper", "chan": "oper"}, event) if CH.ccc(self, "join", {"homechan": "oper", "chan": None}, event): message += CH.ccc(self, "join", {"homechan": "oper", "chan": None}, event) if CH.ccc(self, "part", {"homechan": "oper", "chan": None}, event): message += CH.ccc(self, "part", {"homechan": "oper", "chan": None}, event) if CH.ccc(self, "quit", {"homechan": "admin", "chan": None}, event): message += CH.ccc(self, "quit", {"homechan": "admin", "chan": None}, event) if CH.ccc(self, "reconnect", {"homechan": "oper", "chan": None}, event): message += CH.ccc(self, "reconnect", {"homechan": "oper", "chan": None}, event) if CH.ccc(self, "recovernick", {"homechan": "oper", "chan": None}, event): message += CH.ccc(self, "recovernick", {"homechan": "oper", "chan": None}, event) if CH.ccc(self, "registernick", {"homechan": "owner", "chan": None}, event): message += CH.ccc(self, "registernick", {"homechan": "owner", "chan": None}, event) if CH.ccc(self, "banall", {"homechan": "admin", "chan": None}, event): message += CH.ccc(self, "banall", {"homechan": "oper", "chan": "oper"}, event) if CH.ccc(self, "msg", {"homechan": "oper", "chan": "oper"}, event): message += CH.ccc(self, "msg", {"homechan": "oper", "chan": "oper"}, event) if CH.ccc(self, "act", {"homechan": "oper", "chan": "oper"}, event): message += CH.ccc(self, "act", {"homechan": "oper", "chan": "oper"}, event) if message == font.grey + "Admin: ": # No commands to display. return connection.privmsg(replyto, message[:-2]) elif one == 'quit': if cmdtype == 'help': # Display help text. if len(command.split()) != 1: return connection.privmsg(replyto, "Disconnect and terminate " + connection.get_nickname() + ". Optionally with reason.") connection.privmsg(replyto, font.grey + "Usage: " + font.blue + "!quit " + font.reset + font.italic + "reason") elif cmdtype == "cmd": if not userstatus.atleast_admin(self, event.source.nick, self.network.home_channel): #Insufficient rights. connection.privmsg(replyto, "Denied, you need to have admin (super operator) status or higher in " + font.font.red + self.network.home_channel + font.reset + ".") return if len(command.split()) == 1: log.info("Killed by: " + event.source.nick) self.die(msg = "Killed by " + event.source.nick) else: log.info("Killed by " + event.source.nick + " for " + trigger.split(maxsplit=1)[1]) self.die(msg = "[" + event.source.nick + "] " + trigger.split(maxsplit=1)[1]) elif one == "reconnect": if not userstatus.atleast_oper(self, event.source.nick, self.network.home_channel): connection.privmsg(replyto, "Denied, you need to have operator status or higher in " + font.font.red + self.network.home_channel + font.reset + ".") return if cmdtype == "help": # Display help text. if len(command.split()) != 1: return connection.privmsg(replyto, "Reconnect " + connection.get_nickname() + ". Reason optional.") connection.privmsg(replyto, font.grey + "Usage: " + font.blue + "!reconnect " + font.reset + font.italic + "reason") elif cmdtype == "cmd": if len(command.split()) == 1: self.disconnect(msg = "Reconnect requested by " + event.source.nick) else: self.disconnect(msg = "[" + event.source.nick + "] " + command.split(maxsplit=1)[1]) elif one == "recovernick": if not userstatus.atleast_voiced(self, event.source.nick, self.network.home_channel): connection.privmsg(replyto, "Denied, you need to have voiced status or higher in " + font.font.red + self.network.home_channel + font.reset + ".") return if cmdtype == "help": # Display help text. if len(command.split()) != 1: return connection.privmsg(replyto, "Let " + connection.get_nickname() + " try to recover " + connection.nickname + " as nickname.") elif cmdtype == "cmd": if connection.get_nickname() == connection.nickname: connection.action(replyto, "is already named " + font.font.red + connection.nickname + font.reset + ".") return from common.networkservices import NickServ NickServ.recover_nick(connection, self.password) elif one == "join": if not userstatus.atleast_oper(self, event.source.nick, self.network.home_channel): connection.privmsg(replyto, "Denied, you need to have operator status or higher in " + font.font.red + self.network.home_channel + font.reset + ".") return if cmdtype == "help": #Display help text. if len(command.split()) != 1: return connection.privmsg(replyto, "Make " + connection.get_nickname() + " join a channel. Password optional.") connection.privmsg(replyto, font.grey + "Usage: " + font.blue + self.cmdchar + "join " + font.font.red + font.italic + "channel " + font.reset + font.italic + "password") elif cmdtype == "cmd": try: channel = command.split()[1] except IndexError: connection.privmsg(replyto, "Specify channel. For help type: " + font.blue + self.network.help_character + "join") return try: key = command.split(maxsplit=2)[2] except IndexError: do_everything_to.join(self, connection, channel) return do_everything_to.join(self, connection, channel, key) elif one == "part": if cmdtype == "help": #Display help text. if len(command.split()) != 1: return connection.privmsg(replyto, "Make " + connection.get_nickname() + " part a channel. Reason optional.") connection.privmsg(replyto, font.grey + "Usage: " + font.blue + self.cmdchar + "join " + font.font.red + font.italic + "channel " + font.reset + font.italic + "password") elif cmdtype == "cmd": homeadmin = False if userstatus.atleast_oper(self, event.source.nick, self.network.home_channel): # Is at least operator in home channel. homeadmin = True targetadmin = False if userstatus.atleast_oper(self, event.source.nick, event.target): targetadmin = True if len(command.split()) == 1: # No arguments. if event.target in self.channels: # It's a channel message. if not homeadmin and not targetadmin: # Insufficient rights: connection.privmsg(replyto, "Denied. You need to have at least operator status in " + font.font.red + self.homechan + font.reset + " or " + font.font + event.target + font.reset + ".") return if event.target == self.network.home_channel: connection.action(replyto, "shall not abandon it's home channel!") return connection.part(event.target, event.source.nick) else: # It's a PM. connection.privmsg(replyto, "Specify a channel to part. For help type " + font.blue + self.network.help_character + "part" + font.reset + ".") elif len(command.split()) > 1: # Arguments if command.split()[1] not in self.channels: # First argument is not a channel the bot inhabits. connection.action(replyto, "does not inhabit " + font.red + command.split()[1] + font.reset + ". For help type " + font.blue + self.network.help_character + "part" + font.reset + ".") return if not homeadmin and not userstatus.atleast_oper(self, event.source.nick, command.split()[1]): # Insufficient rights. connection.privmsg(replyto, "Denied. You need to have at least operator status in " + font.red + self.homechan + font.reset + " or " + font.red + command.split()[1] + font.reset + ".") return if command.split()[1] == self.network.home_channel: connection.action("shall not abandon it's home channel!") return try: connection.part(command.split()[1], command.split(maxsplit=2)[2]) except: connection.part(command.split()[1], event.source.nick) elif one == "msg" or command.split(maxsplit=1)[0] == "act": if cmdtype == "help": #Display help text. if len(command.split()) != 1: return if command.split(maxsplit=1)[0] == "act": message = "Let " + connection.get_nickname() + " send an action to a channel." arguments = "action-message" else: message = "Let " + connection.get_nickname() + "send a message to a channel." arguments = "name message" connection.privmsg(replyto, message) connection.privmsg(replyto, font.grey + "Usage: " + font.blue + "!" + command.split(maxsplit=1)[0] + font.reset + font.italic + " target " + arguments) elif cmdtype == "cmd": # Parse user input. try: destination = trigger.split()[1] except IndexError: # User did not specify a destination. connection.privmsg(replyto, "Destination not specified. For help type: " + font.blue + self.network.help_character + command.split(maxsplit=1)[0]) return try: message = trigger.split(maxsplit=2)[2] except IndexError: # User did not specify a message. connection.privmsg(replyto, "Message not specified. For help type: " + font.blue + self.network.help_character + command.split(maxsplit=1)[0]) return # Send the message if user has owner status in the home channel. if self.channels[self.network.home_channel].is_owner(event.source.nick): if destination == connection.get_nickname(): connection.privmsg(replyto, "I just love talking to myself.") return if command.split(maxsplit=1)[0] == "act": connection.action(destination, message) else: connection.privmsg(destination, message) # # Reply error when bot does not inhabit destination channel. # elif destination not in self.channels: # connection.action(replyto, "does not inhabit " + font.red + destination + font.reset + ".") # Send message if user has at least half operator status the home channel or the channel the message is intended for. elif userstatus.atleast_halfop(self, event.source.nick, self.network.home_channel) or userstatus.atleast_halfop(self, event.source.nick, destination): if command.split(maxsplit=1)[0] == "act": connection.action(destination, message) else: if message.startwith('.') or message.startswith('!'): connection.privmsg(replyto, 'I\'d rather not send commands on behalf of anonymous senders. This command is more intended to joke around with people') connection.privmsg(reply, 'If there are complaints about your spamming your rights could be revoked.') return connection.privmsg(destination, message) # Reply error if user is not operator of destination channel. else: connection.privmsg(replyto, "Denied, you need to be an operator of " + font.red + destination + font.reset +".") # elif one == "channelfunctions": # if cmdtype == "help": #Display help text. # Help code block first, as it is impossible to predict for what channel a later command is going to be issued. Rights filtering after help test. # if len(command.split()) != 1: # return # connection.privmsg(replyto, "Display or toggle the status channel functions. Channel, function and value optional. Get a description of a functio via the help argument.") # connection.privmsg(replyto, font.grey + "Usage: " + font.blue + "!channelfunctions " + font.red + font.italic + "channel " + font.reset + font.italic + "function value") # connection.privmsg(replyto, font.grey + "Usage: " + font.blue + "!channelfunctions describe " + font.reset + font.italic + "function") # elif cmdtype == "cmd": # # if len(command.split()) == 1: # No arguments. # if event.target == connection.get_nickname(): # Command issued via PM. # connection.privmsg(replyto, "Nothing to display, Specify a channel.") # else: # Command issued as channel message. # message = AH.get_channelfunctions(self, event.target) # connection.privmsg(replyto, message) # # elif len(command.split()) == 2: # One argument. # if command.split()[1] in self.channels: # Info requested on specific channel. # message = AH.get_channelfunctions(self, command.split()[1]) # connection.privmsg(replyto, message) # else: # First argument is not a channel the bot inhabits. # if not command.split()[1].lower() == "help": # Not a help request. # connection.privmsg(replyto, command.split()[1] + " is not a channel I inhabit. For help type " + font.blue + self.network.help_character + "channelfunctions" + font.reset + ".") # else: # Help request. # connection.privmsg(replyto, "Specify a channel function to get a description of. For help type " + font.blue + self.network.help_character + "channelfunctions" + font.reset + ".") # # elif len(command.split()) == 3: # Two arguments. # channel = event.target # if event.target == connection.get_nickname(): # Command issued via PM. # connection.privmsg(replyto, "One or three arguments required. For help type " + font.blue + self.network.help_character + "channelfunctions" + font.reset + ".") # else: # Command issued via channel. # if not AH.is_channelfunction(command.split()[1]): # First argument is not a channelfunction. # if not command.split()[1].lower() == "describe": # Not a help request. # connection.privmsg(replyto, command.split()[1] + " is not a channel function. For help type " + font.blue + self.network.help_character + "channelfunctions" + font.reset + ".") # return # if not AH.is_channelfunction(command.split()[2]): # Second argument not a channel function. # connection.privmsg(replyto, command.split()[2] + " is not a channel function.") # return # connection.privmsg(replyto, AH.describe_channelfunction(command.split()[2])) # return # # Second argument unsupported. # if not command.split()[2].lower() in ["on", "off"]: # if command.split()[1].lower() == "aggressiveness": # if not AH.is_aggressiveness(command.split()[2].lower()): # Is not an aggressiveness setting. # connection.privmsg(replyto, command.split()[2] + " is not an aggressiveness setting. For help type " + font.blue + self.network.help_character + "channelfunctions" + font.reset + ".") # return # else: # Channel function is not aggresiveness. # connection.privmsg(replyto, "The value of this channel function can only be \"on\" or \"off\". For help type " + font.blue + self.network.help_character + "channelfunctions" + font.reset + ".") # return # if not userstatus.atleast_oper(self, event.source.nick, self.network.home_channel) and not userstatus.atleast_oper(self, event.source.nick, event.target): # Does not have operator status or higher in target or home channel. # connection.privmsg(replyto, "Denied. You need to have at least operator status in " + font.red + event.target + font.reset + " or " + font.red + self.network.home_channel + font.reset + ".") # return # if command.split()[1].lower() == "autojoin" and event.target == self.network.home_channel: # Chaning autojoin of homechannel. # connection.action(replyto, "will always join it's homechannel " + font.red + self.network.home_channel + font.reset + ", regardless of the autojoin function.") # #self.db.run("UPDATE channels SET " + command.split()[1].lower() + "='" + command.split()[2].lower() + "' WHERE name='" + event.target + "' AND network='" + self.network + "'") # self.db.run("UPDATE channels SET " + command.split()[1].lower() + "=%s WHERE name='" + event.target + "' AND network='" + self.network + "'", (command.split()[2].lower(), )) # # elif len(command.split()) == 4: # Three arguments. # if not command.split()[1] in self.channels: # Bot does not inhabit channel to be altered. # connection.privmsg(replyto, command.split()[1] + " is not a channel I inhabit. For help type " + font.blue + self.network.help_character + "channelfunctions" + font.reset + ".") # return # if not AH.is_channelfunction(command.split()[2]): # Function does not exist. # connection.privmsg(replyto, command.split()[2] + " is not a valid channel function. For a list help type: " + font.blue + self.cmdchar + "channelfunctions" + font.red + font.italic + "channel") # return # # if not command.split()[3].lower() in ["on", "off"] and not command.split()[2].lower() == "aggressiveness": # Third argument unsupported. # connection.privmsg(replyto, "The value of this channel function can only be \"on\" or \"off\". For help type " + font.blue + self.network.help_character + "channelfunctions" + font.reset + ".") # return # if not userstatus.atleast_oper(self, event.source.nick, self.network.home_channel) and not userstatus.atleast_oper(self, event.source.nick, command.split()[1]): # Does not have operator status or higher in target or home channel. # connection.privmsg(replyto, "Denied. You need to have at least operator status in " + font.red + event.target + font.reset + " or " + font.red + self.network.home_channel + font.reset + ".") # return # if command.split()[2].lower() == "autojoin" and command.split()[1] == self.network.home_channel: # Chaning autojoin of homechannel. # connection.action(replyto, "will always join it's homechannel " + font.red + self.network.home_channel + font.reset + ", regardless of the autojoin function.") # try: # self.db.run("UPDATE channels SET " + command.split()[2].lower() + "='" + command.split()[3].lower() + "' WHERE LOWER(name)=LOWER('" + command.split()[1] + "') AND network='" + self.network + "'") # except: # connection.privmsg(replyto, "Error, database record not updated.") # return # else: # Too many arguments. # connection.privmsg(replyto, "Too many arguments. For help type " + font.blue + self.network.help_character + "channelfunctions" + font.reset + ".") elif one == "registernick": if not self.channels[self.network.home_channel].is_owner(event.source.nick): #Insufficient rights. connection.privmsg(replyto, "Denied, you need to be the owner of " + font.red + self.network.home_channel + font.reset + ".") return if cmdtype == "help": # Display help text. if len(command.split()) != 1: return connection.privmsg(replyto, "Register with NickServ.") connection.privmsg(replyto, font.grey + "Usage: " + font.blue + self.cmdchar + "registernick " + font.reset + font.italic + "email") elif cmdtype == "cmd": if len(command.split()) == 1: connection.privmsg(replyto, "Insufficient arguments. For help type " + font.blue + self.network.help_character + "registernick" + font.reset + ".") elif len(command.split()) > 2: connection.privmsg(replyto, "Too many arguments. For help type " + font.blue + self.network.help_character + "registernick" + font.reset + ".") elif not self.db.one("SELECT password FROM networks WHERE name='" + self.network + "'"): alphabet = string.ascii_letters + string.digits password = ''.join(secrets.choice(alphabet) for i in range(20)) # 20-character password. self.db.run("UPDATE networks SET password=%s WHERE name=%s", (password, self.network)) connection.privmsg("NickServ", "REGISTER " + password + " " + trigger.split()[1]) else: connection.privmsg("NickServ", "REGISTER " + self.db.one("SELECT password FROM networks WHERE name='" + self.network + "'") + " " + trigger.split()[1]) elif one == "banall": if not self.channels[self.network.home_channel].is_owner(event.source.nick): #Insufficient rights. connection.privmsg(replyto, "Denied, you need to be the owner of " + font.red + self.network.home_channel + font.reset + ".") return if cmdtype == "help": # Display help text. if len(command.split()) != 1: return connection.privmsg(replyto, "Ban all nicknames and usernames for a host in all channels.") connection.privmsg(replyto, font.grey + "Example: " + font.blue + self.cmdchar + "banall " + font.reset + font.italic + "host") elif cmdtype == "cmd": if len(command.split()) == 1: connection.privmsg(replyto, "Insufficient arguments. For help type " + font.blue + self.network.help_character + "banall" + font.reset + ".") elif len(command.split()) > 2: connection.privmsg(replyto, "Too many arguments. For help type " + font.blue + self.network.help_character + "banall" + font.reset + ".") else: labels = trigger.split()[1].split(".") allowed = re.compile("(?!-)[A-Z\d-]{1,63}(? 253: connection.privmsg(replyto, "Host is to long.") elif re.match(r"[0-9]+$", labels[-1]): connection.privmsg(replyto, "The toplevel domain can not containof only numbers.") elif not all(allowed.match(label) for label in labels): connection.privmsg(replyto, "Host contains invalid characters.") elif len(labels) < 2: connection.privmsg(replyto, "Insufficient tuples.") else: for channel in self.channels: connection.mode(channel, "+b *!*@" + trigger.split()[1])