# Part of rabbitears See LICENSE for permissions # Copyright (C) 2022 Matt Arnold import socket import sys import irctokens import time class IRCBadMessage(Exception): pass class IRCError(Exception): pass def printred(s): t = f"\033[1;31m {s} \033[0m\n" print(t) def parsemsg(s): """Breaks a message from an IRC server into its prefix, command, and arguments. """ prefix = '' trailing = [] if not s: raise IRCBadMessage("Empty line.") if s[0] == ':': prefix, s = s[1:].split(' ', 1) if s.find(' :') != -1: s, trailing = s.split(' :', 1) args = s.split() args.append(trailing) else: args = s.split() command = args.pop(0) return prefix, command, args LINEEND = '\r\n' class IRCBot: irc = None def __init__(self, sock, config=None): self.irc = sock self.connected = False self.config = config def send_cmd(self, line): """Send an IRC Command, takes an IRC command string without the CRLF Returns encoded msg on success raises IRCError on failure """ if not self.connected: raise IRCError("Not Connected") encmsg = bytes(line.format() + LINEEND, 'UTF-8' ) expected = len(encmsg) if self.irc.send(encmsg) == expected: return str(encmsg) else: raise IRCError("Unexpected Send Length") def on_welcome(self, *args, **kwargs): authmsg = irctokens.build("NICKSERV", ['IDENTIFY', self.config['nickpass']]) self.send_cmd(authmsg) joinmsg = irctokens.build("JOIN", [self.config['channel']]) self.send_cmd(joinmsg) def send_privmsg(self, dst, msg): msg = irctokens.build("PRIVMSG",[dst, msg]) self.send_cmd(msg) def send_quit(self, quitmsg): msg = irctokens.build("QUIT", [quitmsg]) print(msg) self.send_cmd(msg) def send_action(self, action_msg, dst): pass def connect(self, server, port, channel, botnick, botnickpass): if self.config is None: self.config = {} self.config["hostname"] = server self.config["port"] = port self.config["nick"] = botnick self.config["channel"] = channel self.config["nickpass"] = botnickpass print("Connecting to: " + server) self.irc.connect((self.config["hostname"], self.config["port"])) self.connected = True # Perform user registration usermsg = irctokens.build("USER", [botnick, "0","*", "RabbitEars Bot"]).format() print(usermsg) self.send_cmd(usermsg) nickmsg = irctokens.build("NICK", [botnick]) self.send_cmd(nickmsg) def get_response(self): # Get the response resp = self.irc.recv(4096).decode("UTF-8") msg = parsemsg(resp) nwmsg = irctokens.tokenise(resp) printred(nwmsg.command) if nwmsg.command == "001": self.on_welcome(nwmsg.params) if nwmsg.command == "ERROR": raise IRCError(str(nwmsg.params[0])) if nwmsg.command == 'PING': print('Sending pong') self.irc.send( bytes('PONG ' + LINEEND, "UTF-8")) return msg