Greatly improve channel handling
This also does some more bits of rudimentary user handling, but most of it still remains to be done. Note: This adds DEV_PREFIX to botconfig and LOG_PREFIX to settings (var), make sure to properly update your bot!
This commit is contained in:
parent
49208db148
commit
d090e573b7
@ -35,7 +35,8 @@ DISABLE_DEBUG_MODE_TIME_LORD = False
|
||||
ALT_CHANNELS = ""
|
||||
ALLOWED_ALT_CHANNELS_COMMANDS = []
|
||||
|
||||
DEV_CHANNEL = ""
|
||||
DEV_CHANNEL = "" # Important: Do *not* include the message prefix!
|
||||
DEV_PREFIX = "" # The prefix to send to the dev channel (e.g. "+" will send to "+#dev-chan")
|
||||
PASTEBIN_ERRORS = False # If DEV_CHANNEL is set, errors will be posted there.
|
||||
|
||||
LOG_CHANNEL = "" # Log !fwarns to this channel, if set
|
||||
|
@ -136,7 +136,6 @@
|
||||
"ping_player": "PING! {0} player{1}! ",
|
||||
"already_voted_game": "You have already voted for the {0} game mode.",
|
||||
"vote_game_mode": "\u0002{0}\u0002 votes for the \u0002{1}\u0002 game mode.",
|
||||
"bot_not_opped": "Sorry, I'm not opped in {0}.",
|
||||
"already_playing": "{0}'re already playing!",
|
||||
"too_many_players": "Too many players! Try again next time.",
|
||||
"game_already_running": "Sorry, but the game is already running. Try again next time.",
|
||||
|
@ -7,6 +7,8 @@ from src.logger import debuglog
|
||||
from src import users
|
||||
|
||||
Main = None # main channel
|
||||
Dummy = None # fake channel
|
||||
Dev = None # dev channel
|
||||
|
||||
_channels = {}
|
||||
|
||||
@ -175,7 +177,7 @@ class Channel(IRCContext):
|
||||
if c in status_modes: # op/voice status; keep it here and update the user's registry too
|
||||
if c not in self.modes:
|
||||
self.modes[c] = set()
|
||||
user = users.get(targets[i], allow_bot=True)
|
||||
user = users._get(targets[i], allow_bot=True) # FIXME
|
||||
self.modes[c].add(user)
|
||||
user.channels[self].add(c)
|
||||
i += 1
|
||||
@ -199,7 +201,7 @@ class Channel(IRCContext):
|
||||
else:
|
||||
if c in status_modes:
|
||||
if c in self.modes:
|
||||
user = users.get(targets[i], allow_bot=True)
|
||||
user = users._get(targets[i], allow_bot=True) # FIXME
|
||||
self.modes[c].discard(user)
|
||||
user.channels[self].discard(c)
|
||||
if not self.modes[c]:
|
||||
@ -241,10 +243,10 @@ class FakeChannel(Channel):
|
||||
is_fake = True
|
||||
|
||||
def join(self, key=""):
|
||||
pass # don't actually do anything
|
||||
self.state = _States.Joined
|
||||
|
||||
def part(self, message=""):
|
||||
pass
|
||||
self.state = _States.Left
|
||||
|
||||
def send(self, data, *, notice=False, privmsg=False):
|
||||
debuglog("Would message fake channel {0}: {1!r}".format(self.name, data))
|
||||
|
@ -40,6 +40,42 @@ class IRCContext:
|
||||
return "NOTICE"
|
||||
return "PRIVMSG"
|
||||
|
||||
@staticmethod
|
||||
def _who(cli, target, data=b""):
|
||||
"""Handle WHO requests."""
|
||||
|
||||
if isinstance(data, str):
|
||||
data = data.encode(Features["CHARSET"])
|
||||
elif isinstance(data, int):
|
||||
if data > 0xFFFFFF:
|
||||
data = b""
|
||||
else:
|
||||
data = data.to_bytes(3, "little")
|
||||
|
||||
if len(data) > 3:
|
||||
data = b""
|
||||
|
||||
if "WHOX" in Features:
|
||||
cli.send("WHO", target, b"%tcuihsnfdlar," + data)
|
||||
else:
|
||||
cli.send("WHO", target)
|
||||
|
||||
return int.from_bytes(data, "little")
|
||||
|
||||
def who(self, data=b""):
|
||||
"""Send a WHO request with respect to the server's capabilities.
|
||||
|
||||
To get the WHO replies, add an event listener for "who_result",
|
||||
and an event listener for "who_end" for the end of WHO replies.
|
||||
|
||||
The return value of this function is an integer equal to the data
|
||||
given. If the server supports WHOX, the same integer will be in the
|
||||
event.params.data attribute. Otherwise, this attribute will be 0.
|
||||
|
||||
"""
|
||||
|
||||
return self._who(self.client, self.name, data)
|
||||
|
||||
@staticmethod
|
||||
def _send(data, client, send_type, name):
|
||||
full_address = "{cli.nickname}!{cli.ident}@{cli.hostmask}".format(cli=client)
|
||||
|
@ -5,50 +5,32 @@ import socket
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
from oyoyo.parse import parse_nick
|
||||
|
||||
import botconfig
|
||||
import src.settings as var
|
||||
from src import decorators, wolfgame, errlog as log, stream_handler as alog
|
||||
from src.utilities import irc_equals
|
||||
from src import decorators, wolfgame, channels, hooks, users, errlog as log, stream_handler as alog
|
||||
|
||||
hook = decorators.hook
|
||||
|
||||
def on_privmsg(cli, rawnick, chan, msg, *, notice=False):
|
||||
try:
|
||||
prefixes = getattr(var, "STATUSMSG_PREFIXES")
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
if botconfig.IGNORE_HIDDEN_COMMANDS and chan[0] in prefixes:
|
||||
return
|
||||
if notice and "!" not in rawnick or not rawnick: # server notice; we don't care about those
|
||||
return
|
||||
|
||||
try:
|
||||
getattr(var, "CASEMAPPING")
|
||||
except AttributeError:
|
||||
# some kind of hack for strange networks which don't put server name in some of the NOTICEs on startup
|
||||
if not rawnick:
|
||||
return
|
||||
if notice and "!" not in rawnick and chan in ("*", "AUTH"):
|
||||
# On-connect message before RPL_ISUPPORT is sent.
|
||||
return
|
||||
if chan != botconfig.NICK and botconfig.IGNORE_HIDDEN_COMMANDS and not chan.startswith(tuple(hooks.Features["CHANTYPES"])):
|
||||
return
|
||||
|
||||
log("Server did not send a case mapping; falling back to rfc1459.")
|
||||
var.CASEMAPPING = "rfc1459"
|
||||
|
||||
if (notice and ((not irc_equals(chan, botconfig.NICK) and not botconfig.ALLOW_NOTICE_COMMANDS) or
|
||||
(irc_equals(chan, botconfig.NICK) and not botconfig.ALLOW_PRIVATE_NOTICE_COMMANDS))):
|
||||
if (notice and ((not users.equals(chan, botconfig.NICK) and not botconfig.ALLOW_NOTICE_COMMANDS) or
|
||||
(users.equals(chan, botconfig.NICK) and not botconfig.ALLOW_PRIVATE_NOTICE_COMMANDS))):
|
||||
return # not allowed in settings
|
||||
|
||||
if irc_equals(chan, botconfig.NICK):
|
||||
chan = parse_nick(rawnick)[0]
|
||||
if users.equals(chan, botconfig.NICK):
|
||||
chan = users.parse_rawnick_as_dict(rawnick)["nick"]
|
||||
|
||||
for fn in decorators.COMMANDS[""]:
|
||||
fn.caller(cli, rawnick, chan, msg)
|
||||
|
||||
phase = var.PHASE
|
||||
for x in list(decorators.COMMANDS.keys()):
|
||||
if chan != parse_nick(rawnick)[0] and not msg.lower().startswith(botconfig.CMD_CHAR):
|
||||
if chan != users.parse_rawnick_as_dict(rawnick)["nick"] and not msg.lower().startswith(botconfig.CMD_CHAR):
|
||||
break # channel message but no prefix; ignore
|
||||
if msg.lower().startswith(botconfig.CMD_CHAR+x):
|
||||
h = msg[len(x)+len(botconfig.CMD_CHAR):]
|
||||
@ -61,14 +43,9 @@ def on_privmsg(cli, rawnick, chan, msg, *, notice=False):
|
||||
if phase == var.PHASE:
|
||||
fn.caller(cli, rawnick, chan, h.lstrip())
|
||||
|
||||
|
||||
def unhandled(cli, prefix, cmd, *args):
|
||||
if cmd in decorators.HOOKS:
|
||||
largs = list(args)
|
||||
for i,arg in enumerate(largs):
|
||||
if isinstance(arg, bytes): largs[i] = arg.decode('ascii')
|
||||
for fn in decorators.HOOKS.get(cmd, []):
|
||||
fn.caller(cli, prefix, *largs)
|
||||
for fn in decorators.HOOKS.get(cmd, []):
|
||||
fn.caller(cli, prefix, *args)
|
||||
|
||||
def connect_callback(cli):
|
||||
@hook("endofmotd", hookid=294)
|
||||
@ -76,6 +53,12 @@ def connect_callback(cli):
|
||||
def prepare_stuff(cli, prefix, *args):
|
||||
alog("Received end of MOTD from {0}".format(prefix))
|
||||
|
||||
# This callback only sets up event listeners
|
||||
wolfgame.connect_callback()
|
||||
|
||||
users.Bot = users.User(cli, botconfig.NICK, None, None, None, None, {})
|
||||
users.Bot.modes = set() # only for the bot (user modes)
|
||||
|
||||
# just in case we haven't managed to successfully auth yet
|
||||
if not botconfig.SASL_AUTHENTICATION:
|
||||
cli.ns_identify(botconfig.USERNAME or botconfig.NICK,
|
||||
@ -83,26 +66,24 @@ def connect_callback(cli):
|
||||
nickserv=var.NICKSERV,
|
||||
command=var.NICKSERV_IDENTIFY_COMMAND)
|
||||
|
||||
channels = {botconfig.CHANNEL}
|
||||
channels.Main = channels.add(botconfig.CHANNEL, cli)
|
||||
channels.Dummy = channels.add("*", cli)
|
||||
|
||||
if botconfig.ALT_CHANNELS:
|
||||
channels.update(botconfig.ALT_CHANNELS.split(","))
|
||||
for chan in botconfig.ALT_CHANNELS.split(","):
|
||||
channels.add(chan, cli)
|
||||
|
||||
if botconfig.DEV_CHANNEL:
|
||||
channels.update(chan.lstrip("".join(var.STATUSMSG_PREFIXES)) for chan in botconfig.DEV_CHANNEL.split(","))
|
||||
channels.Dev = channels.add(botconfig.DEV_CHANNEL, cli)
|
||||
|
||||
if var.LOG_CHANNEL:
|
||||
channels.add(var.LOG_CHANNEL.lstrip("".join(var.STATUSMSG_PREFIXES)))
|
||||
channels.add(var.LOG_CHANNEL, cli)
|
||||
|
||||
cli.join(",".join(channels))
|
||||
|
||||
if var.CHANSERV_OP_COMMAND:
|
||||
cli.msg(var.CHANSERV, var.CHANSERV_OP_COMMAND.format(channel=botconfig.CHANNEL))
|
||||
#if var.CHANSERV_OP_COMMAND: # TODO: Add somewhere else if needed
|
||||
# cli.msg(var.CHANSERV, var.CHANSERV_OP_COMMAND.format(channel=botconfig.CHANNEL))
|
||||
|
||||
cli.nick(botconfig.NICK) # very important (for regain/release)
|
||||
|
||||
wolfgame.connect_callback(cli)
|
||||
|
||||
def mustregain(cli, *blah):
|
||||
if not botconfig.PASS:
|
||||
return
|
||||
@ -181,10 +162,4 @@ def connect_callback(cli):
|
||||
"in botconfig.USERNAME if it's different from the bot nick?")
|
||||
cli.quit()
|
||||
|
||||
|
||||
|
||||
@hook("ping")
|
||||
def on_ping(cli, prefix, server):
|
||||
cli.send('PONG', server)
|
||||
|
||||
# vim: set sw=4 expandtab:
|
||||
|
125
src/hooks.py
125
src/hooks.py
@ -13,46 +13,9 @@ from src.logger import plog
|
||||
|
||||
from src import channels, users, settings as var
|
||||
|
||||
### WHO/WHOX requests and responses handling
|
||||
### WHO/WHOX responses handling
|
||||
|
||||
def bare_who(cli, target, data=b""):
|
||||
"""Handle WHO requests."""
|
||||
|
||||
if isinstance(data, str):
|
||||
data = data.encode(Features["CHARSET"])
|
||||
elif isinstance(data, int):
|
||||
if data > 0xFFFFFF:
|
||||
data = b""
|
||||
else:
|
||||
data = data.to_bytes(3, "little")
|
||||
|
||||
if len(data) > 3:
|
||||
data = b""
|
||||
|
||||
if "WHOX" in Features:
|
||||
cli.send("WHO", target, b"%tcuihsnfdlar," + data)
|
||||
else:
|
||||
cli.send("WHO", target)
|
||||
|
||||
return int.from_bytes(data, "little")
|
||||
|
||||
# Always use this function whenever sending out a WHO request!
|
||||
|
||||
def who(target, data=b""):
|
||||
"""Send a WHO request with respect to the server's capabilities.
|
||||
|
||||
To get the WHO replies, add an event listener for "who_result", and
|
||||
an event listener for "who_end" for the end of WHO replies.
|
||||
|
||||
The return value of this function is an integer equal to the data
|
||||
given. If the server supports WHOX, the same integer will be in the
|
||||
event.params.data attribute. Otherwise, this attribute will be 0.
|
||||
|
||||
"""
|
||||
|
||||
return bare_who(target.client, target.name, data)
|
||||
|
||||
#@hook("whoreply")
|
||||
@hook("whoreply")
|
||||
def who_reply(cli, bot_server, bot_nick, chan, ident, host, server, nick, status, hopcount_gecos):
|
||||
"""Handle WHO replies for servers without WHOX support.
|
||||
|
||||
@ -95,17 +58,21 @@ def who_reply(cli, bot_server, bot_nick, chan, ident, host, server, nick, status
|
||||
user = users._add(cli, nick=nick, ident=ident, host=host, realname=realname)
|
||||
|
||||
ch = channels.add(chan, cli)
|
||||
user.channels[ch] = modes
|
||||
ch.users.add(user)
|
||||
for mode in modes:
|
||||
if mode not in ch.modes:
|
||||
ch.modes[mode] = set()
|
||||
ch.modes[mode].add(user)
|
||||
if ch not in user.channels:
|
||||
user.channels[ch] = modes
|
||||
ch.users.add(user)
|
||||
for mode in modes:
|
||||
if mode not in ch.modes:
|
||||
ch.modes[mode] = set()
|
||||
ch.modes[mode].add(user)
|
||||
|
||||
event = Event("who_result", {}, away=is_away, data=0, ip_address=None, server=server, hop_count=hop, idle_time=None, extended_who=False)
|
||||
event.dispatch(var, ch, user)
|
||||
|
||||
#@hook("whospcrpl")
|
||||
if ch is channels.Main and not users.exists(nick): # FIXME
|
||||
users.add(nick, ident=ident,host=host,account="*",inchan=True,modes=modes,moded=set())
|
||||
|
||||
@hook("whospcrpl")
|
||||
def extended_who_reply(cli, bot_server, bot_nick, data, chan, ident, ip_address, host, server, nick, status, hop, idle, account, realname):
|
||||
"""Handle WHOX responses for servers that support it.
|
||||
|
||||
@ -164,17 +131,21 @@ def extended_who_reply(cli, bot_server, bot_nick, data, chan, ident, ip_address,
|
||||
user = users._add(cli, nick=nick, ident=ident, host=host, realname=realname, account=account)
|
||||
|
||||
ch = channels.add(chan, cli)
|
||||
user.channels[ch] = modes
|
||||
ch.users.add(user)
|
||||
for mode in modes:
|
||||
if mode not in ch.modes:
|
||||
ch.modes[mode] = set()
|
||||
ch.modes[mode].add(user)
|
||||
if ch not in user.channels:
|
||||
user.channels[ch] = modes
|
||||
ch.users.add(user)
|
||||
for mode in modes:
|
||||
if mode not in ch.modes:
|
||||
ch.modes[mode] = set()
|
||||
ch.modes[mode].add(user)
|
||||
|
||||
event = Event("who_result", {}, away=is_away, data=data, ip_address=ip_address, server=server, hop_count=hop, idle_time=idle, extended_who=True)
|
||||
event.dispatch(var, ch, user)
|
||||
|
||||
#@hook("endofwho")
|
||||
if ch is channels.Main and not users.exists(nick): # FIXME
|
||||
users.add(nick, ident=ident,host=host,account=account,inchan=True,modes=modes,moded=set())
|
||||
|
||||
@hook("endofwho")
|
||||
def end_who(cli, bot_server, bot_nick, target, rest):
|
||||
"""Handle the end of WHO/WHOX responses from the server.
|
||||
|
||||
@ -196,7 +167,7 @@ def end_who(cli, bot_server, bot_nick, target, rest):
|
||||
|
||||
### Server PING handling
|
||||
|
||||
#@hook("ping")
|
||||
@hook("ping")
|
||||
def on_ping(cli, prefix, server):
|
||||
"""Send out PONG replies to the server's PING requests.
|
||||
|
||||
@ -208,7 +179,7 @@ def on_ping(cli, prefix, server):
|
||||
|
||||
"""
|
||||
|
||||
with cli: # TODO: Make the client a context manager for this to work
|
||||
with cli:
|
||||
cli.send("PONG", server)
|
||||
|
||||
### Fetch and store server information
|
||||
@ -266,7 +237,7 @@ def get_features(cli, rawnick, *features):
|
||||
|
||||
### Channel and user MODE handling
|
||||
|
||||
#@hook("channelmodeis")
|
||||
@hook("channelmodeis")
|
||||
def current_modes(cli, server, bot_nick, chan, mode, *targets):
|
||||
"""Update the channel modes with the existing ones.
|
||||
|
||||
@ -284,7 +255,7 @@ def current_modes(cli, server, bot_nick, chan, mode, *targets):
|
||||
ch = channels.add(chan, cli)
|
||||
ch.update_modes(server, mode, targets)
|
||||
|
||||
#@hook("channelcreate")
|
||||
@hook("channelcreate")
|
||||
def chan_created(cli, server, bot_nick, chan, timestamp):
|
||||
"""Update the channel timestamp with the server's information.
|
||||
|
||||
@ -303,7 +274,7 @@ def chan_created(cli, server, bot_nick, chan, timestamp):
|
||||
|
||||
channels.add(chan, cli).timestamp = int(timestamp)
|
||||
|
||||
#@hook("mode")
|
||||
@hook("mode")
|
||||
def mode_change(cli, rawnick, chan, mode, *targets):
|
||||
"""Update the channel and user modes whenever a mode change occurs.
|
||||
|
||||
@ -320,7 +291,7 @@ def mode_change(cli, rawnick, chan, mode, *targets):
|
||||
|
||||
"""
|
||||
|
||||
actor = users._get(rawnick, allow_none=True, raw_nick=True) # FIXME
|
||||
actor = users._get(rawnick, allow_none=True) # FIXME
|
||||
if chan == users.Bot.nick: # we only see user modes set to ourselves
|
||||
users.Bot.modes.update(mode)
|
||||
return
|
||||
@ -335,7 +306,6 @@ def mode_change(cli, rawnick, chan, mode, *targets):
|
||||
def handle_listmode(cli, chan, mode, target, setter, timestamp):
|
||||
"""Handle and store list modes."""
|
||||
|
||||
return # FIXME
|
||||
ch = channels.add(chan, cli)
|
||||
if mode not in ch.modes:
|
||||
ch.modes[mode] = {}
|
||||
@ -417,7 +387,6 @@ def check_inviteexemptlist(cli, server, bot_nick, chan, target, setter, timestam
|
||||
def handle_endlistmode(cli, chan, mode):
|
||||
"""Handle the end of a list mode listing."""
|
||||
|
||||
return # FIXME
|
||||
ch = channels.add(chan, cli)
|
||||
Event("end_listmode", {}).dispatch(var, ch, mode)
|
||||
|
||||
@ -488,7 +457,7 @@ def end_inviteexemptlist(cli, server, bot_nick, chan, message):
|
||||
|
||||
### NICK handling
|
||||
|
||||
#@hook("nick")
|
||||
@hook("nick")
|
||||
def on_nick_change(cli, old_nick, nick):
|
||||
"""Handle a user changing nicks, which may be the bot itself.
|
||||
|
||||
@ -507,7 +476,7 @@ def on_nick_change(cli, old_nick, nick):
|
||||
|
||||
### JOIN handling
|
||||
|
||||
#@hook("join")
|
||||
@hook("join")
|
||||
def join_chan(cli, rawnick, chan, account=None, realname=None):
|
||||
"""Handle a user joining a channel, which may be the bot itself.
|
||||
|
||||
@ -533,28 +502,28 @@ def join_chan(cli, rawnick, chan, account=None, realname=None):
|
||||
realname = None
|
||||
|
||||
ch = channels.add(chan, cli)
|
||||
ch.state = 2
|
||||
ch.state = channels._States.Joined
|
||||
|
||||
if users.parse_rawnick_as_dict(rawnick)["nick"] == users.Bot.nick: # we may not be fully set up yet
|
||||
ch.mode()
|
||||
ch.mode(Features["CHANMODES"][0])
|
||||
who(ch)
|
||||
ch.who()
|
||||
user = users.Bot
|
||||
|
||||
else:
|
||||
try: # FIXME
|
||||
user = users._get(rawnick, account=account, realname=realname, raw_nick=True)
|
||||
user = users._get(rawnick, account=account, realname=realname)
|
||||
except KeyError:
|
||||
user = users._add(cli, nick=rawnick, account=account, realname=realname, raw_nick=True)
|
||||
user = users._add(cli, nick=rawnick, account=account, realname=realname)
|
||||
|
||||
ch.users.add(user)
|
||||
user.channels[ch] = set()
|
||||
ch.users.add(user)
|
||||
user.channels[ch] = set()
|
||||
|
||||
Event("chan_join", {}).dispatch(var, ch, user)
|
||||
|
||||
### PART handling
|
||||
|
||||
#@hook("part")
|
||||
@hook("part")
|
||||
def part_chan(cli, rawnick, chan, reason=""):
|
||||
"""Handle a user leaving a channel, which may be the bot itself.
|
||||
|
||||
@ -571,7 +540,7 @@ def part_chan(cli, rawnick, chan, reason=""):
|
||||
"""
|
||||
|
||||
ch = channels.add(chan, cli)
|
||||
user = users._get(rawnick, allow_bot=True, raw_nick=True) # FIXME
|
||||
user = users._get(rawnick, allow_bot=True) # FIXME
|
||||
|
||||
if user is users.Bot: # oh snap! we're no longer in the channel!
|
||||
ch._clear()
|
||||
@ -582,7 +551,7 @@ def part_chan(cli, rawnick, chan, reason=""):
|
||||
|
||||
### KICK handling
|
||||
|
||||
#@hook("kick")
|
||||
@hook("kick")
|
||||
def kicked_from_chan(cli, rawnick, chan, target, reason):
|
||||
"""Handle a user being kicked from a channel.
|
||||
|
||||
@ -597,13 +566,13 @@ def kicked_from_chan(cli, rawnick, chan, target, reason):
|
||||
"""
|
||||
|
||||
ch = channels.add(chan, cli)
|
||||
actor = users._get(rawnick, allow_bot=True, raw_nick=True) # FIXME
|
||||
actor = users._get(rawnick, allow_bot=True) # FIXME
|
||||
user = users._get(target, allow_bot=True) # FIXME
|
||||
|
||||
if user is users.Bot:
|
||||
ch._clear()
|
||||
else:
|
||||
ch.remove_user(val)
|
||||
ch.remove_user(user)
|
||||
|
||||
Event("chan_kick", {}).dispatch(var, ch, actor, user, reason)
|
||||
|
||||
@ -618,10 +587,10 @@ def quit(context, message=""):
|
||||
plog("Tried to QUIT but everything was being torn down.")
|
||||
return
|
||||
|
||||
with cli: # TODO: Make the client into a context manager
|
||||
with cli:
|
||||
cli.send("QUIT :{0}".format(message))
|
||||
|
||||
#@hook("quit")
|
||||
@hook("quit")
|
||||
def on_quit(cli, rawnick, reason):
|
||||
"""Handle a user quitting the IRC server.
|
||||
|
||||
@ -639,7 +608,7 @@ def on_quit(cli, rawnick, reason):
|
||||
|
||||
"""
|
||||
|
||||
user = users._get(rawnick, allow_bot=True, raw_nick=True) # FIXME
|
||||
user = users._get(rawnick, allow_bot=True) # FIXME
|
||||
|
||||
for chan in set(user.channels):
|
||||
if user is users.Bot:
|
||||
@ -648,3 +617,5 @@ def on_quit(cli, rawnick, reason):
|
||||
chan.remove_user(user)
|
||||
|
||||
Event("server_quit", {}).dispatch(var, user, reason)
|
||||
|
||||
# vim: set sw=4 expandtab:
|
||||
|
@ -199,6 +199,7 @@ CHANSERV_OP_COMMAND = "OP {channel}"
|
||||
GUEST_NICK_PATTERN = r"^Guest\d+$|^\d|away.+|.+away"
|
||||
|
||||
LOG_CHANNEL = "" # Log !fwarns to this channel, if set
|
||||
LOG_PREFIX = "" # Message prefix for LOG_CHANNEL
|
||||
|
||||
# TODO: move this to a game mode called "fixed" once we implement a way to randomize roles (and have that game mode be called "random")
|
||||
DEFAULT_ROLE = "villager"
|
||||
|
@ -3,7 +3,7 @@ import re
|
||||
|
||||
import botconfig
|
||||
import src.settings as var
|
||||
from src import db
|
||||
from src import channels, db
|
||||
from src.utilities import *
|
||||
from src.decorators import cmd
|
||||
from src.events import Event
|
||||
@ -46,14 +46,14 @@ def decrement_stasis(nick=None):
|
||||
db.expire_stasis()
|
||||
db.init_vars()
|
||||
|
||||
def expire_tempbans(cli):
|
||||
def expire_tempbans():
|
||||
acclist, hmlist = db.expire_tempbans()
|
||||
cmodes = []
|
||||
for acc in acclist:
|
||||
cmodes.append(("-b", "{0}{1}".format(var.ACCOUNT_PREFIX, acc)))
|
||||
for hm in hmlist:
|
||||
cmodes.append(("-b", "*!*@{0}".format(hm)))
|
||||
mass_mode(cli, cmodes, [])
|
||||
channels.Main.mode(*cmodes)
|
||||
|
||||
def parse_warning_target(target, lower=False):
|
||||
if target[0] == "=":
|
||||
@ -677,7 +677,7 @@ def fwarn(cli, nick, chan, rest):
|
||||
reply(cli, nick, chan, messages["fwarn_done"])
|
||||
|
||||
if var.LOG_CHANNEL:
|
||||
cli.msg(var.LOG_CHANNEL, messages["fwarn_log_del"].format(warn_id, warning["target"], hm,
|
||||
cli.msg(var.LOG_PREFIX + var.LOG_CHANNEL, messages["fwarn_log_del"].format(warn_id, warning["target"], hm,
|
||||
warning["reason"], (" | " + warning["notes"]) if warning["notes"] else ""))
|
||||
|
||||
return
|
||||
|
229
src/wolfgame.py
229
src/wolfgame.py
@ -46,7 +46,7 @@ import botconfig
|
||||
import src
|
||||
import src.settings as var
|
||||
from src.utilities import *
|
||||
from src import db, decorators, events, users, logger, proxy, debuglog, errlog, plog
|
||||
from src import db, decorators, events, channels, users, hooks, logger, proxy, debuglog, errlog, plog
|
||||
from src.decorators import cmd, hook, handle_error, event_listener, COMMANDS
|
||||
from src.messages import messages
|
||||
from src.warnings import *
|
||||
@ -90,7 +90,7 @@ var.DISCONNECTED = {} # players who got disconnected
|
||||
|
||||
var.RESTARTING = False
|
||||
|
||||
var.OPPED = False # Keeps track of whether the bot is opped
|
||||
#var.OPPED = False # Keeps track of whether the bot is opped
|
||||
|
||||
var.BITTEN_ROLES = {}
|
||||
var.LYCAN_ROLES = {}
|
||||
@ -124,7 +124,7 @@ if botconfig.DEBUG_MODE and var.DISABLE_DEBUG_MODE_TIME_LORD:
|
||||
|
||||
plog("Loading Werewolf IRC bot")
|
||||
|
||||
def connect_callback(cli):
|
||||
def connect_callback():
|
||||
db.init_vars()
|
||||
SIGUSR1 = getattr(signal, "SIGUSR1", None)
|
||||
SIGUSR2 = getattr(signal, "SIGUSR2", None)
|
||||
@ -151,113 +151,58 @@ def connect_callback(cli):
|
||||
if SIGUSR2:
|
||||
signal.signal(SIGUSR2, sighandler)
|
||||
|
||||
to_be_devoiced = []
|
||||
cmodes = []
|
||||
def who_end(event, var, request):
|
||||
if request == channels.Main.name:
|
||||
if "WHOX" not in hooks.Features:
|
||||
if not var.DISABLE_ACCOUNTS:
|
||||
plog("IRCd does not support accounts, disabling account-related features.")
|
||||
var.DISABLE_ACCOUNTS = True
|
||||
var.ACCOUNTS_ONLY = False
|
||||
|
||||
@hook("quietlist", hookid=294)
|
||||
def on_quietlist(cli, server, botnick, channel, q, quieted, by, something):
|
||||
if re.search(r"^{0}.+\!\*@\*$".format(var.QUIET_PREFIX), quieted): # only unquiet people quieted by bot
|
||||
cmodes.append(("-{0}".format(var.QUIET_MODE), quieted))
|
||||
# Devoice all on connect
|
||||
prefix = "-" + hooks.Features["PREFIX"]["+"]
|
||||
pending = []
|
||||
for user in channels.Main.modes.get(prefix, ()):
|
||||
pending.append((prefix, user.nick))
|
||||
accumulator.send(pending)
|
||||
next(accumulator, None)
|
||||
|
||||
@hook("banlist", hookid=294)
|
||||
def on_banlist(cli, server, botnick, channel, ban, by, timestamp):
|
||||
if re.search(r"^{0}.+\!\*@\*$".format(var.QUIET_PREFIX), ban):
|
||||
cmodes.append(("-{0}".format(var.QUIET_MODE), ban))
|
||||
# Expire tempbans
|
||||
expire_tempbans()
|
||||
|
||||
@hook("whoreply", hookid=295)
|
||||
def on_whoreply(cli, svr, botnick, chan, user, host, server, nick, status, rest):
|
||||
if not var.DISABLE_ACCOUNTS:
|
||||
plog("IRCd does not support accounts, disabling account-related features.")
|
||||
var.DISABLE_ACCOUNTS = True
|
||||
var.ACCOUNTS_ONLY = False
|
||||
players = db.get_pre_restart_state()
|
||||
if players:
|
||||
msg = "PING! " + break_long_message(players).replace("\n", "\nPING! ")
|
||||
channel.Main.send(msg)
|
||||
channel.Main.send(messages["game_restart_cancel"])
|
||||
|
||||
if users.exists(nick, user, host):
|
||||
return
|
||||
events.remove_listener("who_end", who_end)
|
||||
|
||||
if nick == botconfig.NICK:
|
||||
cli.nickname = nick
|
||||
cli.ident = user
|
||||
cli.hostmask = host
|
||||
def end_listmode(event, var, chan, mode):
|
||||
if chan is channels.Main and mode == var.QUIET_MODE:
|
||||
pending = []
|
||||
for quiet in chan.modes.get(mode, ()):
|
||||
if re.search(r"^{0}.+\!\*@\*$".format(var.QUIET_PREFIX), quiet):
|
||||
pending.append(("-" + mode, quiet))
|
||||
accumulator.send(pending)
|
||||
next(accumulator, None)
|
||||
|
||||
if "+" in status:
|
||||
to_be_devoiced.append(nick)
|
||||
newstat = ""
|
||||
for stat in status:
|
||||
if not stat in var.MODES_PREFIXES:
|
||||
continue
|
||||
newstat += var.MODES_PREFIXES[stat]
|
||||
users.add(nick, ident=user,host=host,account="*",inchan=True,modes=set(newstat),moded=set())
|
||||
events.remove_listener("end_listmode", end_listmode)
|
||||
|
||||
@hook("whospcrpl", hookid=295)
|
||||
def on_whoreply(cli, server, nick, ident, host, _, user, status, acc):
|
||||
if users.exists(user, ident, host):
|
||||
return # Don't add someone who is already there
|
||||
if user == botconfig.NICK:
|
||||
cli.nickname = user
|
||||
cli.ident = ident
|
||||
cli.hostmask = host
|
||||
if acc == "0":
|
||||
acc = "*"
|
||||
if "+" in status:
|
||||
to_be_devoiced.append(user)
|
||||
newstat = ""
|
||||
for stat in status:
|
||||
if not stat in var.MODES_PREFIXES:
|
||||
continue
|
||||
newstat += var.MODES_PREFIXES[stat]
|
||||
users.add(user, ident=ident,host=host,account=acc,inchan=True,modes=set(newstat),moded=set())
|
||||
events.add_listener("who_end", who_end)
|
||||
events.add_listener("end_listmode", end_listmode)
|
||||
|
||||
@hook("endofwho", hookid=295)
|
||||
def afterwho(*args):
|
||||
# Devoice all on connect
|
||||
for nick in to_be_devoiced:
|
||||
cmodes.append(("-v", nick))
|
||||
def accumulate_cmodes(count):
|
||||
modes = []
|
||||
for i in range(count):
|
||||
item = yield
|
||||
modes.extend(item)
|
||||
yield i
|
||||
|
||||
# Expire tempbans
|
||||
expire_tempbans(cli)
|
||||
channel.Main.mode(*modes)
|
||||
|
||||
# If the bot was restarted in the middle of the join phase, ping players that were joined.
|
||||
players = db.get_pre_restart_state()
|
||||
if players:
|
||||
msg = "PING! " + break_long_message(players).replace("\n", "\nPING! ")
|
||||
cli.msg(botconfig.CHANNEL, msg)
|
||||
cli.msg(botconfig.CHANNEL, messages["game_restart_cancel"])
|
||||
|
||||
# Unhook the WHO hooks
|
||||
hook.unhook(295)
|
||||
|
||||
|
||||
#bot can be tricked into thinking it's still opped by doing multiple modes at once
|
||||
@hook("mode", hookid=296)
|
||||
def on_give_me_ops(cli, nick, chan, modeaction, target="", *other):
|
||||
if chan != botconfig.CHANNEL:
|
||||
return
|
||||
if modeaction == "+o" and target == botconfig.NICK:
|
||||
var.OPPED = True
|
||||
if users.exists(botconfig.NICK):
|
||||
users.get(botconfig.NICK).modes.add("o")
|
||||
|
||||
if var.PHASE == "none":
|
||||
@hook("quietlistend", hookid=297)
|
||||
def on_quietlist_end(cli, svr, nick, chan, *etc):
|
||||
if chan == botconfig.CHANNEL:
|
||||
mass_mode(cli, cmodes, ["-m"])
|
||||
@hook("endofbanlist", hookid=297)
|
||||
def on_banlist_end(cli, svr, nick, chan, *etc):
|
||||
if chan == botconfig.CHANNEL:
|
||||
mass_mode(cli, cmodes, ["-m"])
|
||||
|
||||
cli.mode(botconfig.CHANNEL, var.QUIET_MODE) # unquiet all
|
||||
elif modeaction == "-o" and target == botconfig.NICK:
|
||||
var.OPPED = False
|
||||
if var.CHANSERV_OP_COMMAND:
|
||||
cli.msg(var.CHANSERV, var.CHANSERV_OP_COMMAND.format(channel=botconfig.CHANNEL))
|
||||
|
||||
|
||||
if var.DISABLE_ACCOUNTS:
|
||||
cli.who(botconfig.CHANNEL)
|
||||
else:
|
||||
cli.who(botconfig.CHANNEL, "%uhsnfa")
|
||||
accumulator = accumulate_cmodes(2)
|
||||
accumulator.send(None)
|
||||
|
||||
@hook("mode") # XXX Get rid of this when the user/channel refactor is done
|
||||
def check_for_modes(cli, rnick, chan, modeaction, *target):
|
||||
@ -308,6 +253,10 @@ def check_for_modes(cli, rnick, chan, modeaction, *target):
|
||||
if "!" not in rnick:
|
||||
sync_modes(cli)
|
||||
|
||||
@cmd("break")
|
||||
def break_stuff(*s):
|
||||
1/0
|
||||
|
||||
def reset_settings():
|
||||
var.CURRENT_GAMEMODE.teardown()
|
||||
var.CURRENT_GAMEMODE = var.GAME_MODES["default"][0]()
|
||||
@ -400,7 +349,7 @@ def refreshdb(cli, nick, chan, rest):
|
||||
"""Updates our tracking vars to the current db state."""
|
||||
db.expire_stasis()
|
||||
db.init_vars()
|
||||
expire_tempbans(cli)
|
||||
expire_tempbans()
|
||||
reply(cli, nick, chan, "Done.")
|
||||
|
||||
@cmd("die", "bye", "fdie", "fbye", flag="D", pm=True)
|
||||
@ -875,9 +824,9 @@ def join_timer_handler(cli):
|
||||
return
|
||||
|
||||
@hook("whoreply", hookid=387)
|
||||
def ping_altpingers_noacc(cli, svr, botnick, chan, ident, host, server, nick, status, rest):
|
||||
def ping_altpingers_noacc(cli, bot_server, bot_nick, chan, ident, host, server, nick, status, hopcount_gecos):
|
||||
if ("G" in status or is_user_stasised(nick) or not var.PINGING_IFS or
|
||||
nick == botnick or nick in pl):
|
||||
nick == bot_nick or nick in pl):
|
||||
return
|
||||
|
||||
ident = irc_lower(ident)
|
||||
@ -888,24 +837,24 @@ def join_timer_handler(cli):
|
||||
var.PINGED_ALREADY.add(hostmask)
|
||||
|
||||
@hook("whospcrpl", hookid=387)
|
||||
def ping_altpingers(cli, server, nick, ident, host, _, user, status, acc):
|
||||
if ("G" in status or is_user_stasised(user) or not var.PINGING_IFS or
|
||||
user == botconfig.NICK or user in pl):
|
||||
def ping_altpingers(cli, bot_server, bot_nick, data, chan, ident, ip_address, host, server, nick, status, hop, idle, account, realname):
|
||||
if ("G" in status or is_user_stasised(nick) or not var.PINGING_IFS or
|
||||
nick == botconfig.NICK or nick in pl):
|
||||
|
||||
return
|
||||
|
||||
# Create list of players to ping
|
||||
acc = irc_lower(acc)
|
||||
account = irc_lower(account)
|
||||
ident = irc_lower(ident)
|
||||
host = host.lower()
|
||||
if acc and acc != "*":
|
||||
if acc in chk_acc:
|
||||
to_ping.append(user)
|
||||
var.PINGED_ALREADY_ACCS.add(acc)
|
||||
if account and account != "*":
|
||||
if account in chk_acc:
|
||||
to_ping.append(nick)
|
||||
var.PINGED_ALREADY_ACCS.add(account)
|
||||
|
||||
elif not var.ACCOUNTS_ONLY:
|
||||
hostmask = ident + "@" + host
|
||||
to_ping.append(user)
|
||||
to_ping.append(nick)
|
||||
var.PINGED_ALREADY.add(hostmask)
|
||||
|
||||
@hook("endofwho", hookid=387)
|
||||
@ -926,8 +875,9 @@ def join_timer_handler(cli):
|
||||
|
||||
cli.msg(botconfig.CHANNEL, msg)
|
||||
|
||||
# FIXME
|
||||
if not var.DISABLE_ACCOUNTS:
|
||||
cli.who(botconfig.CHANNEL, "%uhsnfa")
|
||||
cli.who(botconfig.CHANNEL, "%tcuihsnfdlar,")
|
||||
else:
|
||||
cli.who(botconfig.CHANNEL)
|
||||
|
||||
@ -1067,12 +1017,6 @@ def join_player(cli, player, chan, who=None, forced=False, *, sanity=True):
|
||||
if chan != botconfig.CHANNEL:
|
||||
return False
|
||||
|
||||
if not var.OPPED:
|
||||
cli.notice(who, messages["bot_not_opped"].format(chan))
|
||||
if var.CHANSERV_OP_COMMAND:
|
||||
cli.msg(var.CHANSERV, var.CHANSERV_OP_COMMAND.format(channel=botconfig.CHANNEL))
|
||||
return False
|
||||
|
||||
if users.exists(player):
|
||||
ident = irc_lower(users.get(player).ident)
|
||||
host = users.get(player).host.lower()
|
||||
@ -1222,7 +1166,7 @@ def kill_join(cli, chan):
|
||||
# use this opportunity to expire pending stasis
|
||||
db.expire_stasis()
|
||||
db.init_vars()
|
||||
expire_tempbans(cli)
|
||||
expire_tempbans()
|
||||
if var.AFTER_FLASTGAME is not None:
|
||||
var.AFTER_FLASTGAME()
|
||||
var.AFTER_FLASTGAME = None
|
||||
@ -1241,11 +1185,6 @@ def fjoin(cli, nick, chan, rest):
|
||||
return
|
||||
noticed = False
|
||||
fake = False
|
||||
if not var.OPPED:
|
||||
cli.notice(nick, messages["bot_not_opped"].format(chan))
|
||||
if var.CHANSERV_OP_COMMAND:
|
||||
cli.msg(var.CHANSERV, var.CHANSERV_OP_COMMAND.format(channel=botconfig.CHANNEL))
|
||||
return
|
||||
if not rest.strip():
|
||||
evt.data["join_player"](cli, nick, chan, forced=True)
|
||||
|
||||
@ -2565,7 +2504,7 @@ def stop_game(cli, winner="", abort=False, additional_winners=None, log=True):
|
||||
|
||||
reset_modes_timers(cli)
|
||||
reset()
|
||||
expire_tempbans(cli)
|
||||
expire_tempbans()
|
||||
|
||||
# This must be after reset()
|
||||
if var.AFTER_FLASTGAME is not None:
|
||||
@ -3283,15 +3222,15 @@ def on_join(cli, raw_nick, chan, acc="*", rname=""):
|
||||
if nick in var.DCED_PLAYERS.keys():
|
||||
var.PLAYERS[nick] = var.DCED_PLAYERS.pop(nick)
|
||||
if nick == botconfig.NICK:
|
||||
var.OPPED = False
|
||||
#var.OPPED = False
|
||||
cli.send("NAMES " + chan)
|
||||
if nick == var.CHANSERV and not var.OPPED and var.CHANSERV_OP_COMMAND:
|
||||
cli.msg(var.CHANSERV, var.CHANSERV_OP_COMMAND.format(channel=botconfig.CHANNEL))
|
||||
#if nick == var.CHANSERV and not var.OPPED and var.CHANSERV_OP_COMMAND:
|
||||
# cli.msg(var.CHANSERV, var.CHANSERV_OP_COMMAND.format(channel=botconfig.CHANNEL))
|
||||
|
||||
@hook("namreply")
|
||||
def on_names(cli, _, __, *names):
|
||||
if "@" + botconfig.NICK in names:
|
||||
var.OPPED = True
|
||||
#@hook("namreply")
|
||||
#def on_names(cli, _, __, *names):
|
||||
# if "@" + botconfig.NICK in names:
|
||||
# var.OPPED = True
|
||||
|
||||
@cmd("goat", playing=True, phases=("day",))
|
||||
def goat(cli, nick, chan, rest):
|
||||
@ -6787,17 +6726,16 @@ def show_admins(cli, nick, chan, rest):
|
||||
|
||||
var.ADMIN_PINGING = True
|
||||
|
||||
@hook("whoreply", hookid=4)
|
||||
def on_whoreply(cli, server, _, chan, ident, host, ___, user, status, ____):
|
||||
if not var.ADMIN_PINGING:
|
||||
def admin_whoreply(event, var, chan, user):
|
||||
if not var.ADMIN_PINGING or chan is not channels.Main:
|
||||
return
|
||||
|
||||
if is_admin(user) and "G" not in status and user != botconfig.NICK:
|
||||
admins.append(user)
|
||||
if is_admin(user.nick): # FIXME: Using the old interface for now; user.is_admin() is better
|
||||
if user is not users.Bot and not event.params.away:
|
||||
admins.append(user.nick) # FIXME
|
||||
|
||||
@hook("endofwho", hookid=4)
|
||||
def show(*args):
|
||||
if not var.ADMIN_PINGING:
|
||||
def admin_endwho(event, var, target):
|
||||
if not var.ADMIN_PINGING or target != channels.Main.name:
|
||||
return
|
||||
|
||||
admins.sort(key=str.lower)
|
||||
@ -6806,10 +6744,15 @@ def show_admins(cli, nick, chan, rest):
|
||||
|
||||
reply(cli, nick, chan, msg)
|
||||
|
||||
hook.unhook(4)
|
||||
var.ADMIN_PINGING = False
|
||||
|
||||
cli.who(botconfig.CHANNEL)
|
||||
events.remove_listener("who_result", admin_whoreply)
|
||||
events.remove_listener("who_end", admin_endwho)
|
||||
|
||||
events.add_listener("who_result", admin_whoreply)
|
||||
events.add_listener("who_end", admin_endwho)
|
||||
|
||||
channels.Main.who()
|
||||
|
||||
@cmd("coin", pm=True)
|
||||
def coin(cli, nick, chan, rest):
|
||||
|
@ -45,6 +45,14 @@ except ImportError:
|
||||
"", "- The lykos developers", sep="\n")
|
||||
sys.exit(1)
|
||||
|
||||
try: # FIXME
|
||||
botconfig.DEV_PREFIX
|
||||
except AttributeError:
|
||||
print("Please set up your config to include a DEV_PREFIX variable",
|
||||
"If you have a prefix in your DEV_CHANNEL config, move it out into DEV_PREFIX",
|
||||
sep="\n")
|
||||
sys.exit(1)
|
||||
|
||||
from oyoyo.client import IRCClient
|
||||
|
||||
import src
|
||||
|
Loading…
Reference in New Issue
Block a user