diff --git a/bot.py b/bot.py index 624a3c8..0d8fb8c 100755 --- a/bot.py +++ b/bot.py @@ -1,127 +1,69 @@ #!/usr/bin/python3 -import socket, rich, asyncio, time, re, ssl +import socket, rich, asyncio, time, re, ssl, ircstates from config import * -class bot: - def raw(msg): - """ - Sends a raw message using the socket s - """ - s.send(f"{msg}\n".encode('utf-8')) - class logger: - async def log(msg=None, level=0, color=False): - if level <= DebugLVL: - if color: - rich.print(msg); - else: - print(msg); - async def handle(line): - if (line[0].endswith('.tilde.chat') and (line[1] == 'NOTICE' or line[1] == '001' or line[1] == '002' or line[1] == '003' or line[1] == '004' or line[1] == '005' or line[1] == '372' or line[1] == '251' or line[1] == '252' or line[1] == '253' or line[1] == '254' or line[1] == '255' or line[1] == '265' or line[1] == '266' or line[1] == '375' or line[1] == '376' or line[1] == '396') ): - loglevel = 450 - elif line[0].endswith('.tilde.chat'): - loglevel = 441 - elif line[0] == ':NickServ!services@services.tilde.chat': - if (line[3] == ':This' or line[3] == ':nick,' or line[2] == ':please' or line[3] == ':If' or line[3] == ':Password'): - loglevel = 450 - else: - loglevel = 441 - elif line[0] == ':ChanServ!services@services.tilde.chat': - loglevel = 442 - elif line[0] == 'PING': - loglevel = 443 - else: - loglevel = 440 - await bot.logger.log(f"{' '.join(line)}", loglevel); +def _send(msg: str, log=True): + s.send(f"{msg}\n".encode('utf-8')) + if log == True: print(f"> {msg}") - class get: - def nick(hostmask): - return hostmask[1:].split('!')[0] - def ident(hostmask): - return hostmask[1:].split('!')[1].split('@')[0] - def host(hostmask): - return hostmask[1:].split('!')[1].split('@')[1] +def usermodes(chan, user): + try: + return srv.channels[chan].users[user].modes + except: + return [] - def nslogin(): - bot.raw(f"PRIVMSG NickServ@services.tilde.chat :IDENTIFY {NICK} {SERVICES_PW}") - bot.raw(f"MODE {NICK} +B") +def is_admin(source): + return 'julian@envs.net' == source.split('!')[1] - async def joinchans(): - bot.raw(f"JOIN {CHANNELS}") - await bot.logger.log(f"[bold]Joined channels: [magenta]{CHANNELS}[/magenta] per request of [magenta]-!-[/magenta][/bold]", color=True) - - async def join(channel, requser="-!-", prefixmsg="Joined"): - bot.raw(f"JOIN :{channel}") - await bot.logger.log(f"[bold]{prefixmsg} [magenta]{channel}[/magenta] per request of [magenta]{requser}[/magenta][/bold]", color=True) - - async def part(channel, msg="Bye, I'be worked enough", requser="-!-"): - bot.raw(f"PART {channel} :{msg}") - await bot.logger.log(f"[bold]Leaved [magenta]{channel}[/magenta] per request of [magenta]{requser}[/magenta][/bold]", color=True) - - async def topic(channel, topic="You should set a topic", requser="-!-"): - bot.raw(f"TOPIC {channel} :{topic}") - await bot.logger.log(f"[bold]Topic of [magenta]{channel}[/magenta] channeged to [blue]{topic}[/blue] per request of [magenta]{requser}[/magenta][/bold]", color=True) - time.sleep(1) - bot.raw(f"PRIVMSG {channel} :Changed topic of {channel}") - - async def quit(msg="Bye, I'be worked enough", requser="-!-"): - bot.raw(f"QUIT :{msg}") - await bot.logger.log(f"[bold]Exiting per request of [magenta]{requser}[/magenta] with message of [magenta]{msg}[/magenta][/bold]", color=True) - - async def setup(): - bot.nslogin() - await bot.joinchans() - async def ConnectionSetup(): - bot.raw(f"NICK {NICK}") - bot.raw(f"USER {NICK} 0 * :{REALNAME}") - class Handeler: - async def newmsg(line): - if (line[0] == "PING"): - bot.raw(f"PONG {line[1]}") - elif (line[0] == ':NickServ!services@services.tilde.chat' and line[1] == 'NOTICE' and line[2] == 'util' and line[3] == ':If'): - await bot.setup() - elif (line[1] == "INVITE" and line[2] == NICK): - await bot.join(line[3][1:], line[0][1:], prefixmsg="Invited to"); - time.sleep(1) - bot.raw(f"PRIVMSG {line[3][1:]} :Hello, I'm a bot that joined because {line[0][1:]} invited me.") - elif (line[1] == 'PRIVMSG' and line[2] != NICK and line[3] == ":*.help"): - bot.raw(f"PRIVMSG {line[2]} :I am a utility bot.") - elif (line[1] == 'PRIVMSG' and line[3] == ":*.join"): - await bot.join(line[4], line[0][1:]); - time.sleep(1) - bot.raw(f"PRIVMSG {line[4]} :Hello, I'm a bot that joined because {bot.get.nick(line[0])} told me to.") - elif (line[1] == 'PRIVMSG' and line[3] == ":*.part" and ( (line[4] != "#lounge" and line[4] != "#lounge-ops" and line[4] != "#airstrip") or line[0][1:] == 'julian!julian@envs.net') ): - await bot.part(line[4], f"Leaving per request of {bot.get.nick(line[0])}", line[0][1:]); - elif (line[1] == 'PRIVMSG' and line[2] != NICK and line[3] == ":*.topic" and ((line[2]!="#lounge" and line[2]!="#lounge-ops" and line[2]!="#airstrip") or line[0][1:]=='julian!julian@envs.net') ): - await bot.topic(line[2], ' '.join(line[4:]) ,line[0][1:]) - elif (line[1] == 'PRIVMSG' and line[2] != NICK and line[3] == ":*.echo"): - bot.raw(f"PRIVMSG {line[2]} :\x033[Echo]\x0F \x032{bot.get.nick(line[0])}\x0F said: \x039{' '.join(line[4:])}") - elif (line[1] == 'PRIVMSG' and line[2] != NICK and line[3] == ":*.psa" and ((line[4]!="#lounge" and line[4]!="#lounge-ops" and line[4]!="#airstrip") or line[0][1:]=='julian!julian@envs.net') ): - if (line[4].startswith('#')): - bot.raw(f"PRIMSG {line[4]} :\x0307[Public Service Anouncement]\x0F {' '.join(line[5:])}") - await bot.logger.log(f"[bold]PSA by [magenta]{line[0][1:]}[/magenta] -> [magenta]{line[4]}[/magenta] -> [blue]{' '.join(line[5:])}[/blue][/bold]", color=True) - else: - bot.raw(f"PRIVMSG {bot.get.nick(line[0])} :Sorry, the syntax for PSA is: *.psa ") - -readbuffer="" +def nslogin(): + _send(f"PRIVMSG NickServ@services.tilde.chat :IDENTIFY {NICK} {SERVICES_PW}", log=False) + print("Logged into services") + _send(f"MODE {NICK} +B") + _send(f"JOIN {CHANNELS}") + for i in db['chan'].all(): + _send(f"JOIN {[i['name']]}") +def joinchannel(channel): + _send(f"JOIN {channel}") + db['chan'].insert(dict(name=i)) +srv = ircstates.Server(NETNAME) s = socket.socket() ctx = ssl.create_default_context(purpose=ssl.Purpose.CLIENT_AUTH) if tls == True: s = ctx.wrap_socket(s) s.connect((HOST, PORT)) -asyncio.run(bot.ConnectionSetup()) +_send(f"NICK {NICK}") +_send(f"USER {NICK} 0 * :{REALNAME}") -while True: - readbuffer = readbuffer + s.recv(2048).decode('utf-8') - temp = str.split(readbuffer, "\n") - readbuffer = temp.pop() +try: + while True: + recv_data = s.recv(1024) + recv_lines = srv.recv(recv_data) - for line in temp: - line = str.rstrip(line) - line = str.split(line) + for line in recv_lines: + srv.parse_tokens(line) - asyncio.run(bot.Handeler.newmsg(line)) - asyncio.run(bot.logger.handle(line)) + if line.command == "PING": _send(f"PONG :{line.params[0]}", log=False) + elif (line.source == f"NickServ!{SERVICES_HOSTMASK}" and line.command == 'NOTICE' and line.params == ['util','If you do not change within 1 minute, I will change your nick.']): nslogin() + elif (line.command == "INVITE" and line.params[0] == NICK): joinchannel(line.params[1]) + elif line.command == "!botlist": _send(f"PRIVMSG {line.source} :I am a utility bot. Public commands *.echo | Ran by ~julian@~team/~jmjl@{~town,~club}") + elif (line.command == "PRIVMSG" and line.params[1].startswith('*.') ): + commandargs = line.params[1].split(' ') + command = ''.join(commandargs[0].split('*.')[1:]) + args = commandargs[1:] + usernick = line.source.split('!')[0] + chan = line.params[0] + if command == "join" and is_admin(line.source): joinchannel(args[0]) + elif command == "help": _send(f"PRIVMSG {chan} :I am a utility bot. Ran by ~julian@~team/~jmjl@{~town,~club}") + elif command == "echo": _send(f"PRIVMSG {chan} :\x033[Echo]\x0F \x032{usernick}\x0F said: \x039{' '.join(args[0:])}") + elif command == "psa" and args[0].startswith('#'): + if 'o' in usermodes(args[0], usernick) or 'q' in usermodes(args[0], usernick): _send(f"PRIVMSG {args[0]} :\x0307**PSA:\x0F {' '.join(args[1:])}") + else: _send(f"PRIVMSG {usernick} :Sorry, you aren't allowed to make public service anouncements.") + elif command == "psa" and not args[0].startswith('#'): _send(f"PRIVMSG {usernick} :Sorry, the syntax for PSA is: *.psa ") + elif ('o' in usermodes(chan, usernick) or 'q' in usermodes(chan, usernick)) or is_admin(line.source): + if command == "part": _send(f"PART {args[0]} :Leaving per request of {usernick}") + if command == "topic": _send(f"TOPIC {chan} :{' '.join(args[0:])}") +except KeyboardInterrupt: _send("QUIT :^C") diff --git a/config.py b/config.py index e36c476..de41d47 100644 --- a/config.py +++ b/config.py @@ -1,5 +1,6 @@ #!/usr/bin/python3 from fileread import fileload +import dataset DebugLVL = 442 HOST = fileload('conf/host') @@ -8,4 +9,7 @@ NICK = fileload('conf/nick') REALNAME = fileload('conf/realname') SERVICES_PW = fileload('conf/pw') CHANNELS = fileload('conf/chans') +NETNAME = fileload('conf/net') +SERVICES_HOSTMASK = fileload('conf/services') tls = fileload('conf/port') == '6697' +db = dataset.connect('sqlite:///conf/database.db') diff --git a/requirements.txt b/requirements.txt index 3f382dd..b0a5525 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ -rich +ircstates +dataset