FireBot/handlers.py

253 lines
8.6 KiB
Python
Raw Normal View History

2023-11-20 23:52:18 +00:00
#!/usr/bin/python3
2023-11-09 03:20:50 +00:00
import random as r
import config as conf
import commands as cmds
2023-11-18 05:23:46 +00:00
from typing import Union, Callable
2023-11-09 03:20:50 +00:00
from overrides import bytes, bbytes
from importlib import reload
2023-11-20 23:52:18 +00:00
import bare, re, checks
2024-05-23 18:12:46 +00:00
from traceback import format_exc
2023-11-09 03:20:50 +00:00
2023-11-09 21:37:08 +00:00
def CTCP(bot: bare.bot, msg: str) -> bool:
sender = msg.split("!", 1)[0][1:]
2023-11-09 03:20:50 +00:00
kind = msg.split("\x01")[1].split(" ", 1)[0]
bot.log(f'Responding to CTCP "{kind}" from {sender}')
if kind == "VERSION":
bot.notice(
f"\x01VERSION FireBot {conf.__version__} (https://git.amcforum.wiki/Firepup650/fire-ircbot)\x01",
sender,
True,
)
return True
elif kind == "USERINFO":
bot.notice("\x01USERINFO FireBot (Firepup's bot)\x01", sender, True)
return True
elif kind == "SOURCE":
bot.notice(
"\x01SOURCE https://git.amcforum.wiki/Firepup650/fire-ircbot\x01",
sender,
True,
)
return True
elif kind == "FINGER":
bot.notice("\x01FINGER Firepup's bot\x01", sender, True)
return True
elif kind == "CLIENTINFO":
bot.notice(
"\x01CLIENTINFO ACTION VERSION USERINFO SOURCE FINGER\x01", sender, True
)
return True
bot.log(f'Unknown CTCP "{kind}"', "WARN")
return False
2023-11-09 21:37:08 +00:00
2023-11-18 05:23:46 +00:00
def PRIVMSG(bot: bare.bot, msg: str) -> Union[tuple[None, None], tuple[str, str]]:
2023-11-09 03:20:50 +00:00
# Format of ":[Nick]![ident]@[host|vhost] PRIVMSG [channel] :[message]”
name = msg.split("!", 1)[0][1:]
host = msg.split("@", 1)[1].split(" ", 1)[0]
2024-02-15 03:17:08 +00:00
bot.tmpHost = host
bridge = False
2023-11-20 23:52:18 +00:00
bot.current = "user"
2023-11-15 05:26:02 +00:00
if (
(name.startswith("saxjax") and bot.server == "efnet")
or (name in ["ReplIRC", "sshchat"] and bot.server == "replirc")
2023-11-21 02:18:48 +00:00
or (
name in ["FirePyLink_", "FirePyLink"]
and bot.server in ["ircnow", "backupbox"]
)
2023-11-15 05:26:02 +00:00
):
2023-11-15 00:50:26 +00:00
if "<" in msg and ">" in msg:
bridge = True
2023-11-20 23:52:18 +00:00
bot.current = "bridge"
2023-11-09 03:20:50 +00:00
Nname = msg.split("<", 1)[1].split(">", 1)[0].strip()
if name == "ReplIRC":
name = Nname[4:]
elif name in ["FirePyLink_", "FirePyLink"]:
name = Nname.lstrip("@%~+")[3:-1]
2023-11-09 03:20:50 +00:00
else:
name = Nname
message = msg.split(">", 1)[1].strip()
else:
2023-11-09 21:37:08 +00:00
message = msg.split("PRIVMSG", 1)[1].split(":", 1)[1].strip()
2023-11-09 03:20:50 +00:00
elif name == bot.nick:
2023-11-09 21:42:17 +00:00
return None, None
2023-11-09 03:20:50 +00:00
else:
message = msg.split("PRIVMSG", 1)[1].split(":", 1)[1].strip()
chan = msg.split("PRIVMSG", 1)[1].split(":", 1)[0].strip()
2023-11-24 07:15:33 +00:00
message = conf.sub(message, bot, chan, name)
if chan in bot.ignores:
return None, None
2023-11-09 03:20:50 +00:00
bot.log(
2023-11-20 23:52:18 +00:00
f'Got "{bytes(message).lazy_decode()}" from "{name}" in "{chan}" ({bot.current})',
2023-11-09 03:20:50 +00:00
)
if len(name) > bot.nicklen:
bot.log(f"Name too long ({len(name)} > {bot.nicklen})")
if not bridge:
return None, None
else:
bot.log("This user is a bridge, overriding")
2023-11-09 03:20:50 +00:00
elif chan not in bot.channels:
if not chan == bot.nick:
bot.log(
f"Channel not in channels ({chan} not in {bot.channels})",
"WARN",
)
2023-11-09 03:20:50 +00:00
if not chan.startswith(("#", "+", "&")):
chan = name
else:
bot.channels[chan] += 1
if "goat" in name.lower() and bot.gmode == True:
cmds.goat(bot, chan, name, message)
handled = False
for cmd in cmds.data:
triggers = [cmd]
triggers.extend(cmds.data[cmd]["aliases"])
2023-12-05 04:48:56 +00:00
triggers = list(conf.sub(call, bot, chan, name).lower() for call in triggers)
if conf.cmdFind(
2023-12-05 04:48:56 +00:00
conf.sub(message, bot, chan, name).lower(),
2023-11-09 03:20:50 +00:00
triggers,
cmds.data[cmd]["prefix"],
):
2023-11-21 02:18:48 +00:00
if "check" in cmds.data[cmd] and cmds.data[cmd]["check"]:
2023-11-20 23:52:18 +00:00
if cmds.data[cmd]["check"](bot, name, host, chan, cmd):
2024-05-23 18:12:46 +00:00
try:
cmds.call[cmd](bot, chan, name, message)
except Exception:
Err = format_exc()
for line in Err.split("\n"):
bot.log(line, "ERROR")
2024-05-24 17:06:41 +00:00
bot.msg(
"Sorry, I had an error trying to execute that command. Please check error logs.",
chan,
)
2023-11-09 03:20:50 +00:00
else:
2024-05-24 17:06:41 +00:00
try:
cmds.call[cmd](bot, chan, name, message)
except Exception:
Err = format_exc()
for line in Err.split("\n"):
bot.log(line, "ERROR")
bot.msg(
"Sorry, I had an error trying to execute that command. Please check error logs.",
chan,
)
2023-11-09 03:20:50 +00:00
handled = True
break
if not handled:
2023-11-20 23:52:18 +00:00
for check in cmds.regexes:
2023-11-09 03:20:50 +00:00
if re.search(
2023-12-05 04:48:56 +00:00
conf.sub(check, bot, chan, name),
2023-11-09 03:20:50 +00:00
message,
):
cmds.call[check](bot, chan, name, message)
handled = True
break
if not handled and conf.cmdFind(message, ["reload", "r"]):
2023-11-20 23:52:18 +00:00
if checks.admin(bot, name, host, chan, "reload"):
2023-11-09 21:42:17 +00:00
return "reload", chan
2023-11-09 03:20:50 +00:00
handled = True
if not handled and len(message.split("\x01")) == 3:
2023-11-09 21:36:34 +00:00
if not CTCP(bot, message):
kind = message.split("\x01")[1]
2024-04-07 05:38:49 +00:00
if kind.startswith("ACTION ducks") and len(kind.split(" ", 2)) == 3:
2023-11-09 03:20:50 +00:00
bot.msg(
2023-11-09 21:36:34 +00:00
f"\x01ACTION gets hit by {kind.split(' ', 2)[2]}\x01",
2023-11-09 03:20:50 +00:00
chan,
)
2024-02-15 03:17:08 +00:00
elif kind == "ACTION ducks":
bot.msg("\x01ACTION gets hit by a duck\x01", chan)
2024-05-11 01:51:14 +00:00
if chan in bot.channels and bot.channels[chan] >= bot.interval:
2024-05-11 00:43:14 +00:00
sel = ""
bot.channels[chan] = 0
2024-05-11 00:43:14 +00:00
if bot.autoMethod == "QUOTE":
r.seed()
with open("mastermessages.txt", "r") as mm:
sel = conf.decode_escapes(
r.sample(mm.readlines(), 1)[0].replace("\\n", "").replace("\n", "")
)
else:
sel = bot.markov.generate_from_sentence(message)
bot.msg(f"[{bot.autoMethod}] {sel}", chan)
2023-11-09 21:42:17 +00:00
return None, None
2023-11-18 03:24:10 +00:00
2023-11-18 05:23:46 +00:00
def NICK(bot: bare.bot, msg: str) -> tuple[None, None]:
name = msg.split("!", 1)[0][1:]
if name == bot.nick:
bot.nick = msg.split("NICK", 1)[1].split(":", 1)[1].strip()
return None, None
2023-11-18 03:24:10 +00:00
2023-11-18 05:23:46 +00:00
def KICK(bot: bare.bot, msg: str) -> tuple[None, None]:
important = msg.split("KICK", 1)[1].split(":", 1)[0].strip().split(" ")
channel = important[0]
kicked = important[1]
if kicked == bot.nick:
bot.channels.pop(channel, None)
return None, None
2023-11-18 03:24:10 +00:00
2023-11-18 05:23:46 +00:00
def PART(bot: bare.bot, msg: str) -> tuple[None, None]:
parted = msg.split("!", 1)[0][1:]
2023-11-18 03:24:10 +00:00
channel = msg.split("PART", 1)[1].split(":", 1)[0].strip()
if parted == bot.nick:
bot.channels.pop(channel, None)
return None, None
2023-11-09 21:37:08 +00:00
2024-05-01 20:41:32 +00:00
def QUIT(bot: bare.bot, msg: str) -> tuple[None, None]:
if bot.server == "replirc":
2024-05-01 02:19:28 +00:00
quitter = msg.split("!", 1)[0][1:]
if quitter == "FireMCbot":
bot.send("TOPIC #firemc :FireMC Relay channel (offline)\n")
return None, None
2023-11-18 03:24:10 +00:00
2024-05-01 20:41:32 +00:00
2024-05-18 22:38:49 +00:00
def JOIN(bot: bare.bot, msg: str) -> tuple[None, None]:
2024-05-19 03:23:36 +00:00
nick = msg.split("!", 1)[0][1:]
hostname = msg.split("@", 1)[1].split(" ", 1)[0].strip()
chan = msg.split("#")[-1].strip()
conf.dnsblHandler(bot, nick, hostname, chan)
2024-05-18 22:38:49 +00:00
return None, None
def MODE(bot: bare.bot, msg: str) -> tuple[None, None]:
chan = msg.split("#", 1)[1].split(" ", 1)[0]
add = True if msg.split("#", 1)[1].split(" ", 2)[1][0] == "+" else False
modes = msg.split("#", 1)[1].split(" ", 2)[1][1:]
users = ""
try:
users = msg.split("#", 1)[1].split(" ", 2)[2].split()
2024-05-24 17:06:41 +00:00
except IndexError:
...
if len(modes) != len(users):
bot.log("Refusing to handle modes that do not have corresponding users.")
return None, None
for i in range(len(modes)):
if users[i] == bot.nick:
if modes[i] == "o":
bot.ops[chan] = add
bot.log(f"{'Got' if add else 'Lost'} ops in {chan}")
return None, None
def NULL(bot: bare.bot, msg: str) -> tuple[None, None]:
return None, None
2023-11-21 02:18:48 +00:00
handles: dict[
str, Callable[[bare.bot, str], Union[tuple[None, None], tuple[str, str]]]
] = {
"PRIVMSG": PRIVMSG,
"NICK": NICK,
"KICK": KICK,
"PART": PART,
"MODE": MODE,
"TOPIC": NULL,
2024-05-01 20:41:32 +00:00
"QUIT": QUIT,
2024-05-18 22:38:49 +00:00
"JOIN": JOIN,
"NOTICE": NULL,
"INVITE": NULL,
}