import secrets, string from common import userstatus, do_everything_to from commands.common import CommandHelpers as CH from commands.common import AdminHelpers as AH bold = "\x02" italic = "\x1D" underline = "\x1F" reverse = "\x16" # swap background and foreground colors ("reverse video") reset = "\x0F" blue = "\x0302" green = "\x0303" red = "\x0304" grey = "\x0314" def do_command(self, connection, event): cmdtype, trigger, command, replyto = CH.disect_command(self, event) # Do nothing if there is no command. if not command: return try: command.split()[0] except: return # Ignore channel commands from users that do not have at least voice in homechannel or operator status in target channel. if event.type == "pubmsg": # It's a channel message. if not userstatus.atleast_oper(self, event.source.nick, self.homechannel) and not userstatus.atleast_oper(self, event.source.nick, event.target): # Does not have at least voiced status in homechannel or operator status in target channel. return if command.split()[0] == "opme" and event.target == connection.get_nickname() and self.channels[self.homechannel].is_oper(event.source.nick): # It's a PM and sender is admin in homechannel. # Keep the command secret. print(1111) if len(command.split()) == 2: # Stop silently if there is not exactly 1 argument. print(22222) if command.split()[1] in self.channels.lower(): # Stop silently if thebot is not in the requested channel. print(33333) connection.mode(command.split()[2], "+ohv " + event.source.nick + " " + event.source.nick + " " + event.source.nick) elif command == "cmd" or command == "cmds" or command == "commands": if cmdtype == "cmd": message = grey + "Admin: " if CH.ccc(self, "channelfunctions", {"homechan": "oper", "chan": "oper"}, event): message += CH.ccc(self, "channelfunctions", {"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, "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 == grey + "Admin: ": # No commands to display. return connection.privmsg(replyto, message[:-2] + ".") elif command.split()[0] == "quit": if not userstatus.atleast_admin(self, event.source.nick, self.homechannel): #Insufficient rights. connection.privmsg(replyto, "Denied, you need to have admin (super operator) status or higher in " + red + self.homechannel + reset + ".") return if cmdtype == "help": # Display help text. if len(command.split()) is not 1: return connection.privmsg(replyto, "Disconnect and terminate " + connection.get_nickname() + ". Optionally with reason.") connection.privmsg(replyto, grey + "Usage: " + blue + "!quit " + reset + italic + "reason") elif cmdtype == "cmd": if len(command.split()) == 1: self.die(msg = "Killed by " + event.source.nick) else: self.die(msg = "[" + event.source.nick + "] " + command.split(maxsplit=1)[1]) elif command.split()[0] == "reconnect": if not userstatus.atleast_oper(self, event.source.nick, self.homechannel): connection.privmsg(replyto, "Denied, you need to have operator status or higher in " + red + self.homechannel + reset + ".") return if cmdtype == "help": # Display help text. if len(command.split()) is not 1: return connection.privmsg(replyto, "Reconnect " + connection.get_nickname() + ". Reason optional.") connection.privmsg(replyto, grey + "Usage: " + blue + "!reconnect " + reset + 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 command.split()[0] == "recovernick": if not userstatus.atleast_voiced(self, event.source.nick, self.homechannel): connection.privmsg(replyto, "Denied, you need to have voiced status or higher in " + red + self.homechannel + reset + ".") return if cmdtype == "help": # Display help text. if len(command.split()) is not 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 " + red + connection.nickname + reset + ".") return from common.networkservices import NickServ NickServ.recover_nick(connection, self.password) elif command.split()[0] == "join": if not userstatus.atleast_oper(self, event.source.nick, self.homechannel): connection.privmsg(replyto, "Denied, you need to have operator status or higher in " + red + self.homechannel + reset + ".") return if cmdtype == "help": #Display help text. if len(command.split()) is not 1: return connection.privmsg(replyto, "Make " + connection.get_nickname() + " join a channel. Password optional.") connection.privmsg(replyto, grey + "Usage: " + blue + self.cmdchar + "join " + red + italic + "channel " + reset + italic + "password") elif cmdtype == "cmd": try: channel = command.split()[1] except IndexError: connection.privmsg(replyto, "Specify channel. For help type: " + blue + self.helpchar + "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 command.split()[0] == "part": if cmdtype == "help": #Display help text. if len(command.split()) is not 1: return connection.privmsg(replyto, "Make " + connection.get_nickname() + " part a channel. Reason optional.") connection.privmsg(replyto, grey + "Usage: " + blue + self.cmdchar + "join " + red + italic + "channel " + reset + italic + "password") elif cmdtype == "cmd": homeadmin = False if userstatus.atleast_oper(self, event.source.nick, self.homechannel): # 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 " + red + self.homechan + reset + " or " + red + event.target + reset + ".") return if event.target == self.homechannel: connection.action("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 " + blue + self.helpchar + "part" + 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 " + red + command.split()[1] + reset + ". For help type " + blue + self.helpchar + "part" + 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 " + red + self.homechan + reset + " or " + red + command.split()[1] + reset + ".") return if command.split()[1] == self.homechannel: 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 command.split()[0] == "msg" or command.split(maxsplit=1)[0] == "act": if cmdtype == "help": #Display help text. if len(command.split()) is not 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, grey + "Usage: " + blue + "!" + command.split(maxsplit=1)[0] + reset + 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: " + blue + self.helpchar + 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: " + blue + self.helpchar + command.split(maxsplit=1)[0]) return # Send the message if user has owner status in the home channel. if self.channels[self.homechannel].is_owner(event.source.nick): if destination == connection.get_nickname(): connection.privmsg(replyto, "To prevent dying in a loop I shall not message 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 " + red + destination + reset + ".") # Send message if user has at least operator status the home channel or the channel the message is intended for. elif userstatus.atleast_oper(self, event.source.nick, self.homechannel) or userstatus.atleast_oper(self, event.source.nick, destination): if command.split(maxsplit=1)[0] == "act": connection.action(destination, message) else: 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 " + red + destination + reset +".") elif command.split()[0] == "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()) is not 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, grey + "Usage: " + blue + "!channelfunctions " + red + italic + "channel " + reset + italic + "function value") connection.privmsg(replyto, grey + "Usage: " + blue + "!channelfunctions describe " + reset + 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 " + blue + self.helpchar + "channelfunctions" + reset + ".") else: # Help request. connection.privmsg(replyto, "Specify a channel function to get a description of. For help type " + blue + self.helpchar + "channelfunctions" + 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 " + blue + self.helpchar + "channelfunctions" + 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 " + blue + self.helpchar + "channelfunctions" + 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 " + blue + self.helpchar + "channelfunctions" + 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 " + blue + self.helpchar + "channelfunctions" + reset + ".") return if not userstatus.atleast_oper(self, event.source.nick, self.homechannel) 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 " + red + event.target + reset + " or " + red + self.homechannel + reset + ".") return if command.split()[1].lower() == "autojoin" and event.target == self.homechannel: # Chaning autojoin of homechannel. connection.action(replyto, "will always join it's homechannel " + red + self.homechannel + 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 " + blue + self.helpchar + "channelfunctions" + 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: " + blue + self.cmdchar + "channelfunctions" + red + 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 " + blue + self.helpchar + "channelfunctions" + reset + ".") return if not userstatus.atleast_oper(self, event.source.nick, self.homechannel) 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 " + red + event.target + reset + " or " + red + self.homechannel + reset + ".") return if command.split()[2].lower() == "autojoin" and command.split()[1] == self.homechannel: # Chaning autojoin of homechannel. connection.action(replyto, "will always join it's homechannel " + red + self.homechannel + 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 " + blue + self.helpchar + "channelfunctions" + reset + ".") elif command.split()[0] == "registernick": if not self.channels[self.homechannel].is_owner(event.source.nick): #Insufficient rights. connection.privmsg(replyto, "Denied, you need to be the owner of " + red + self.homechannel + reset + ".") return if cmdtype == "help": # Display help text. if len(command.split()) is not 1: return connection.privmsg(replyto, "Register with NickServ.") connection.privmsg(replyto, grey + "Usage: " + blue + self.cmdchar + "registernick " + reset + italic + "email") elif cmdtype == "cmd": if len(command.split()) == 1: connection.privmsg(replyto, "Insufficient arguments. For help type " + blue + self.helpchar + "registernick" + reset + ".") elif len(command.split()) > 2: connection.privmsg(replyto, "Too many arguments. For help type " + blue + self.helpchar + "registernick" + 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.action("NickServ", "REGISTER " + self.db.one("SELECT password FROM networks WHERE name='" + self.network + "'") + " " + trigger.split()[1])