diff --git a/commands.py b/commands.py index 1b7801a..6c3ed0e 100644 --- a/commands.py +++ b/commands.py @@ -1,3 +1,6 @@ +from functools import wraps + + class Command: def __init__(self, config): self.config = config @@ -6,10 +9,14 @@ class Command: def mesg(self, msg): self.util.mesg(msg) + def send(self, msg): + self.util.send(msg) + def err_perm(self, level="admin"): self.mesg(f"Error: insufficient privileges, you lack {level} access") def adm(func, *args, **kwargs): + """decorator for admin commands""" global adm_cmds try: if func.__name__ not in adm_cmds and func.__name__ != "_": @@ -19,6 +26,7 @@ class Command: if func.__name__ not in adm_cmds and func.__name__ != "_": adm_cmds.append(func.__name__) + @wraps(func) def _(self, *args, **kwargs): if func.__name__ == "help": self.admin_commands = adm_cmds @@ -40,6 +48,7 @@ class Command: return _ def cmd(func, *args, **kwargs): + """decorator for user commands""" global cmds try: if func.__name__ not in cmds and func.__name__ != "_": @@ -49,6 +58,7 @@ class Command: if func.__name__ not in cmds and func.__name__ != "_": cmds.append(func.__name__) + @wraps(func) def _(self, *args, **kwargs): if func.__name__ == "help": self.commands = cmds @@ -66,6 +76,13 @@ class Command: return _ + def internal(func, *args, **kwargs): + """decorator for commands like ctcp which are for internal use, but use normal args template""" + global cmds + if func.__name__ in cmds: + cmds.remove(func.__name__) + return func + def preq_cmd(self): # command prequisites / triggers cmd = self.line if cmd == "help" or cmd.startswith("help "): @@ -76,11 +93,31 @@ class Command: command = "dbg" elif cmd == "dbg2" or cmd.startswith("dbg2 "): command = "dbg2" + elif cmd.startswith("\x01"): + command = "ctcp" else: return if command not in self.config.cmd.disabled: eval(f"self.{command}()") + @internal + @cmd + def ctcp(self, prefix, cmd, pm, line, admin, mesg): + """CTCP responses""" + ctcp = cmd[1:] + if ctcp.startswith("PING"): + if not ctcp.endswith("\x01"): + ctcp = ctcp + "\x01" + self.send(f"NOTICE {self.util.target} \x01" + ctcp) + elif ctcp.startswith("SOURCE"): + self.send( + f"NOTICE {self.util.target} \x01SOURCE " + + self.config.self.source + + "\x01" + ) + elif ctcp.startswith("CLIENTINFO"): + self.send(f"NOTICE {self.util.target} \x01CLIENTINFO PING SOURCE\x01") + @adm def quit(self, prefix, cmd, pm, line, admin, mesg): if admin and (cmd == "q" or cmd == "quit"): @@ -88,10 +125,6 @@ class Command: elif is_adm and (cmd.startswith("q ") or cmd.startswith("quit ")): self.util.quit(cmd.split(" ", 1)[1]) - @adm - def dbg2(self, prefix, cmd, pm, line, admin, mesg): - mesg(dir(self)) - @adm def dbg(self, prefix, cmd, pm, line, admin, mesg): """temporary debug command, subject to change A LOT""" diff --git a/config.py b/config.py index b047bee..2e00309 100644 --- a/config.py +++ b/config.py @@ -3,6 +3,7 @@ class config: nick = "bot6" username = "jan6_bot" realname = "jan6's bot" + source = "https://tildegit.org/jan6/bot6" class server: name = "tilde.chat" diff --git a/stuff.py b/stuff.py index 80bae16..392d85e 100755 --- a/stuff.py +++ b/stuff.py @@ -45,6 +45,7 @@ def stuff(bot, sock): command, command.util, config, util, prefixes, admin_accounts, admin_users, admin_only = ( configure() ) + send = util.send send(irctokens.build("NICK", [config.self.nick]).format()) send( @@ -59,7 +60,11 @@ def stuff(bot, sock): for line in recv_lines: server.parse_tokens(line) - print(f"< {line.format()}") + stri = line.format() + for k, v in util.dict.items(): + stri = stri.replace(k, v) + print(f"< {stri}") + del stri if line.command == "PING": send(f"PONG :{line.params[0]}") @@ -120,7 +125,10 @@ def stuff(bot, sock): except IndexError: continue # skip to next command cmd = "echo IndexError or something" - prefix = prefix or None + try: + prefix = prefix or None + except UnboundLocalError: + prefix = None cmd = cmd.strip() try: is_adm = ( @@ -129,6 +137,8 @@ def stuff(bot, sock): ) except KeyError: is_adm = line.source in admin_users + + # update command module's info dynamically for line info command.util.target = target command._line = line command.pm = is_pm @@ -137,11 +147,13 @@ def stuff(bot, sock): command.config = config command.self_nick = self_nick command.prefix = prefix + if is_adm and cmd.startswith("reload"): command, command.util, config, util, prefixes, admin_accounts, admin_users, admin_only = ( configure() ) util.target = target + send = util.send command._line = line command.pm = is_pm command.line = cmd @@ -149,6 +161,7 @@ def stuff(bot, sock): command.config = config command.self_nick = self_nick command.prefix = prefix + command.util = util command.util.target = target mesg("reloaded") elif ( diff --git a/util.py b/util.py index 07eb200..30ed98b 100644 --- a/util.py +++ b/util.py @@ -6,9 +6,46 @@ class Util: self.sock = sock self.config = config self.target = "" + self.dict = { + "\x00": "\\x00", + "\x01": "\\x01", + "\x02": "\\x02", + "\x03": "\\x03", + "\x04": "\\x04", + "\x05": "\\x05", + "\x06": "\\x06", + "\x07": "\\x07", + "\x08": "\\x08", + "\x09": "\\x09", + "\x0a": "\\x0a", + "\x0b": "\\x0b", + "\x0c": "\\x0c", + "\x0d": "\\x0d", + "\x0e": "\\x0e", + "\x0f": "\\x0f", + "\x10": "\\x10", + "\x11": "\\x11", + "\x12": "\\x12", + "\x13": "\\x13", + "\x14": "\\x14", + "\x15": "\\x15", + "\x16": "\\x16", + "\x17": "\\x17", + "\x18": "\\x18", + "\x19": "\\x19", + "\x1a": "\\x1a", + "\x1b": "\\x1b", + "\x1c": "\\x1c", + "\x1d": "\\x1d", + "\x1e": "\\x1e", + "\x1f": "\\x1f", + } def send(self, raw: str): - print(f"> {raw}") + stri = raw + for k, v in self.dict.items(): + stri = stri.replace(k, v) + print(f"> {stri}") self.sock.sendall(f"{raw}\r\n".encode("utf8")) def quit(self, msg=None):