import irctokens from config import config as Config from util import Util from commands import Command from youtube import YouTube import sys, importlib, time def stuff(bot, sock): config = Config util = Util(config, sock) command = Command(config) server = bot.server send = util.send def mesg(msg: str, t=None): util.mesg(msg, t) # mesg=util.mesg server_caps = [] wanted_caps = config.capabilities chan = config.server.channel # main channel autojoin_done = False is_ctcp = False is_pm = False mode = "init" nick_override = False def auth( nick=config.self.nick, passwd=config.server.nickserv_pass, auth="nickserv", nickserv_auth=config.server.nickserv_auth, ): # TODO: handle auth that isn't nickserv if auth.lower() == "nickserv": # line.source.split("!")[0] # TODO: on most network can probably do "PRIVMSG NickServ@services. :help" # TODO: support actually checking the nickserv mask properly if nickserv_auth: nick_override = True if config.server.nickserv_squery: util.send( irctokens.build( "SQUERY", ["NickServ", f"IDENTIFY {nick} {passwd}"] ).format() ) util.send( irctokens.build( "SQUERY", ["NickServ", f"{config.server.nickserv_recover} {nick}"], ).format() ) else: util.mesg(f"IDENTIFY {nick} {passwd}", config.server.nickserv_path) util.mesg( f"{config.server.nickserv_recover} {nick}", config.server.nickserv_path, ) # attempt to re-nick just in case send(irctokens.build("NICK", [config.self.nick]).format()) def configure(): config = importlib.reload(sys.modules["config"]).config util = Util(config, sock) command = importlib.reload(sys.modules["commands"]).Command(config) command.YouTube = importlib.reload(sys.modules["youtube"]).YouTube command.util = util command.YouTube.util = util prefixes = config.cmd.prefixes admin_accounts = config.admin.accounts admin_users = config.admin.hostmasks admin_only = config.cmd.admin_only return ( command, command.util, config, util, prefixes, admin_accounts, admin_users, admin_only, ) ( 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( irctokens.build( "USER", [config.self.username, "0", "*", config.self.realname] ).format() ) while True: self_nick = server.nickname recv_data = sock.recv(1024) recv_lines = server.recv(recv_data) for line in recv_lines: try: server.parse_tokens(line) except IndexError: print("\x1b[31;1mNGIRCD SUCKS\x1b[0m ", line) continue stri = line.format() for k, v in util.dict.items(): stri = stri.replace(k, v) print(f"{time.strftime('%H:%M:%S')} < {stri}") del stri if line.command == "PING": send(f"PONG :{line.params[0]}") if mode == "init": if line.command == "NOTICE" and line.source != None: if util.maskmatch(line.source, config.server.nickserv_mask): if config.server.nickserv_auth == True: auth() if line.command == "433": # 433 is ERR_NICKNAMEINUSE util.nick(config.self.nick + "_") if ( line.command == "376" or line.command == "422" ): # 376 is RPL_ENDOFMOTD and 422 is ERR_NOMOTD if config.server.nickserv_auth == True: auth() send(irctokens.build("CAP", ["LS", "302"]).format()) elif line.command == "CAP" and line.params[1] == "LS": if server_caps == []: server_caps = line.params[2].split() caps = [value for value in wanted_caps if value in server_caps] # single-send is more efficient # BUT a single invalid cap == no caps enabled at all!!! send(irctokens.build("CAP", ["REQ", " ".join(caps)]).format()) # for i in caps: # send(irctokens.build("CAP", ["REQ",i]).format()) send(irctokens.build("CAP", ["END"]).format()) mode = "boot" elif mode == "boot": send(irctokens.build("JOIN", [chan]).format()) mode = "normal" elif mode == "normal" and autojoin_done == False: try: for channel in config.server.autojoin: send("JOIN " + channel) time.sleep(0.25) except Exception: True autojoin_done = True elif mode == "normal": if line.command == "433" and nick_override != False: mesg("nick in use!", chan) util.nick(config.self.nick) nick_override = False else: nick_override = False if line.command == "INVITE": ( send(irctokens.build("JOIN", [line.params[1]]).format()) if line.params[1] not in config.server.blacklisted_channels else None ) elif line.command == "PRIVMSG": if line.tags == None or "batch" not in line.tags: is_pm = False is_ctcp = False target = line.params[0] if target == self_nick: target = line.source.split("!")[0] is_pm = True util.target = target command.util.target = target cmd = line.params[1] if cmd != "" and ( is_pm or cmd.startswith(self_nick) or cmd[0] in prefixes or "https://" in cmd or "http://" in cmd ): # TODO: allow ignoring hostmasks if line.hostmask.nickname in config.cmd.ignored_nicks: continue try: # if message in a channel, remove prefixes if is_pm: command.prefix = None else: if cmd[0] in prefixes: cmd = cmd.replace(cmd[0], "", 1) command.prefix = cmd[0] elif cmd.startswith(self_nick + ":"): cmd = cmd.replace(self_nick + ":", "", 1) command.prefix = self_nick elif cmd.startswith(self_nick): cmd = cmd.replace(self_nick, "", 1) command.prefix = self_nick else: command.prefix = None except IndexError: continue # skip to next command cmd = "echo IndexError or something" try: prefix = command.prefix or None except UnboundLocalError or AttributeError: prefix = None command.prefix = prefix cmd = cmd.strip() try: is_adm = ( line.tags["account"] in admin_accounts or line.source in admin_users ) except ( KeyError, TypeError, ): # either no account tag, or no tags at all is_adm = line.source in admin_users # update command module's info dynamically for line info command.util.target = target command._line = line command.is_ctcp = is_ctcp command.pm = is_pm command.line = cmd command.admin = is_adm 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 command.admin = is_adm command.config = config command.self_nick = self_nick command.prefix = prefix command.util = util command.util.target = target mesg("reloaded") elif ( cmd.startswith("eval ") and "eval" not in config.cmd.disabled ): if is_adm: try: result = eval( cmd[len("eval ") :].strip() or "None" ) except Exception as e: mesg("Error: " + str(e)) else: mesg("Error: you're not authorized to eval") elif ( cmd.startswith("exec ") and "exec" not in config.cmd.disabled ): if is_adm: try: result = exec( cmd[len("exec ") :].strip() or "None" ) except Exception as e: mesg("Error: " + str(e)) else: mesg("Error: you're not authorized to exec") # handle normal commands else: command.preq_cmd()