def handle_listmode(cli, chan, mode, target, setter, timestamp): """Handle and store list modes.""" ch = channels.add(chan, cli) if mode not in ch.modes: ch.modes[mode] = {} ch.modes[mode][target] = (setter, int(timestamp))
def mode_change(cli, rawnick, chan, mode, *targets): """Update the channel and user modes whenever a mode change occurs. Ordering and meaning of arguments for a MODE change: 0 - The IRCClient instance (like everywhere else) 1 - The raw nick of the mode setter/actor 2 - The channel (target) of the mode change 3 - The mode changes * - The targets of the modes (if any) This takes care of properly updating all relevant users and the channel modes to make sure we remain internally consistent. """ actor = users._add(cli, nick=rawnick) # FIXME if chan == users.Bot.nick: # we only see user modes set to ourselves users.Bot.modes.update(mode) return target = channels.add(chan, cli) target.queue("mode_change", { "mode": mode, "targets": targets }, (var, actor, target))
def mode_change(cli, rawnick, chan, mode, *targets): """Update the channel and user modes whenever a mode change occurs. Ordering and meaning of arguments for a MODE change: 0 - The IRCClient instance (like everywhere else) 1 - The raw nick of the mode setter/actor 2 - The channel (target) of the mode change 3 - The mode changes * - The targets of the modes (if any) This takes care of properly updating all relevant users and the channel modes to make sure we remain internally consistent. """ if chan == users.Bot.nick: # we only see user modes set to ourselves users.Bot.modes.update(mode) return if "!" not in rawnick: # Only sync modes if a server changed modes because # 1) human ops probably know better # 2) other bots might start a fight over modes # 3) recursion; we see our own mode changes. evt = Event("sync_modes", {}) evt.dispatch(var) return actor = users._get(rawnick, allow_none=True) # FIXME target = channels.add(chan, cli) target.queue("mode_change", {"mode": mode, "targets": targets}, (var, actor, target))
def mode_change(cli, rawnick, chan, mode, *targets): """Update the channel and user modes whenever a mode change occurs. Ordering and meaning of arguments for a MODE change: 0 - The IRCClient instance (like everywhere else) 1 - The raw nick of the mode setter/actor 2 - The channel (target) of the mode change 3 - The mode changes * - The targets of the modes (if any) This takes care of properly updating all relevant users and the channel modes to make sure we remain internally consistent. """ if chan == users.Bot.nick: # we only see user modes set to ourselves users.Bot.modes.update(mode) return if "!" not in rawnick: # Only sync modes if a server changed modes because # 1) human ops probably know better # 2) other bots might start a fight over modes # 3) recursion; we see our own mode changes. evt = Event("sync_modes", {}) evt.dispatch(var) return actor = users._get(rawnick, allow_none=True) # FIXME target = channels.add(chan, cli) target.queue("mode_change", { "mode": mode, "targets": targets }, (var, actor, target))
def prepare_stuff(cli, prefix, *args): from src import lagcheck alog("Received end of MOTD from {0}".format(prefix)) # This callback only sets up event listeners wolfgame.connect_callback() # just in case we haven't managed to successfully auth yet if botconfig.PASS and not botconfig.SASL_AUTHENTICATION: cli.ns_identify(botconfig.USERNAME or botconfig.NICK, botconfig.PASS, nickserv=var.NICKSERV, command=var.NICKSERV_IDENTIFY_COMMAND) # give bot operators an opportunity to do some custom stuff here if they wish event = Event("irc_connected", {}) event.dispatch(var, cli) # don't join any channels if we're just doing a lag check if not lagcheck: channels.Main = channels.add(botconfig.CHANNEL, cli) channels.Dummy = channels.add("*", cli) if botconfig.ALT_CHANNELS: for chan in botconfig.ALT_CHANNELS.split(","): channels.add(chan, cli) if botconfig.DEV_CHANNEL: channels.Dev = channels.add(botconfig.DEV_CHANNEL, cli) if var.LOG_CHANNEL: channels.add(var.LOG_CHANNEL, cli) else: alog("Preparing lag check") # if we ARE doing a lagcheck, we need at least our own host or things break users.Bot.who() users.Bot.change_nick(botconfig.NICK) if var.SERVER_PING_INTERVAL > 0: def ping_server_timer(cli): ping_server(cli) t = threading.Timer(var.SERVER_PING_INTERVAL, ping_server_timer, args=(cli, )) t.daemon = True t.start() ping_server_timer(cli) hook.unhook(294)
def who_reply(cli, bot_server, bot_nick, chan, ident, host, server, nick, status, hopcount_gecos): """Handle WHO replies for servers without WHOX support. Ordering and meaning of arguments for a bare WHO response: 0 - The IRCClient instance (like everywhere else) 1 - The server the requester (i.e. the bot) is on 2 - The nickname of the requester (i.e. the bot) 3 - The channel the request was made on 4 - The ident of the user in this reply 5 - The hostname of the user in this reply 6 - The server the user in this reply is on 7 - The nickname of the user in this reply 8 - The status (H = Not away, G = Away, * = IRC operator, @ = Opped in the channel in 4, + = Voiced in the channel in 4) 9 - The hop count and realname (gecos) This fires off the "who_result" event, and dispatches it with three arguments, the game state namespace, a Channel, and a User. Less important attributes can be accessed via the event.params namespace. """ hop, realname = hopcount_gecos.split(" ", 1) hop = int(hop) # We throw away the information about the operness of the user, but we probably don't need to care about that # We also don't directly pass which modes they have, since that's already on the channel/user is_away = ("G" in status) modes = {Features["PREFIX"].get(s) for s in status} - {None} user = users._add(cli, nick=nick, ident=ident, host=host, realname=realname) # FIXME ch = None if not channels.predicate(chan): # returns True if it's not a channel ch = channels.add(chan, cli) 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) 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())
def join_chan(cli, rawnick, chan, account=None, realname=None): """Handle a user joining a channel, which may be the bot itself. Ordering and meaning of arguments for a channel JOIN: 0 - The IRCClient instance (like everywhere else) 1 - The raw nick (nick!ident@host) of the user joining the channel 2 - The channel the user joined The following two arguments are optional and only present if the server supports the extended-join capability (we will have requested it when we connected if it was supported): 3 - The account the user is identified to, or "*" if none 4 - The realname (gecos) of the user, or "" if none """ if account == "*": account = None if realname == "": realname = None ch = channels.add(chan, cli) user = users.get(nick=rawnick, account=account, allow_bot=True, allow_none=True, allow_ghosts=True) if user is None: user = users.add(cli, nick=rawnick, account=account) if account: # ensure we work for the case when user left, changed accounts, then rejoined as a different account user.account = account user = users.get(nick=rawnick, account=account) ch.users.add(user) user.channels[ch] = set() # mark the user as here, in case they used to be connected before but left user.disconnected = False Event("chan_join", {}).dispatch(ch, user) if user is users.Bot: ch.mode() ch.mode(Features["CHANMODES"][0]) ch.who()
def current_modes(cli, server, bot_nick, chan, mode, *targets): """Update the channel modes with the existing ones. Ordering and meaning of arguments for a bare MODE response: 0 - The IRCClient instance (like everywhere else) 1 - The server the requester (i.e. the bot) is on 2 - The nickname of the requester (i.e. the bot) 3 - The channel holding the modes 4 - The modes of the channel * - The targets to the modes (if any) """ ch = channels.add(chan, cli) ch.update_modes(server, mode, targets)
def prepare_stuff(cli, prefix, *args): from src import lagcheck alog("Received end of MOTD from {0}".format(prefix)) # This callback only sets up event listeners wolfgame.connect_callback() # just in case we haven't managed to successfully auth yet if botconfig.PASS and not botconfig.SASL_AUTHENTICATION: cli.ns_identify(botconfig.USERNAME or botconfig.NICK, botconfig.PASS, nickserv=var.NICKSERV, command=var.NICKSERV_IDENTIFY_COMMAND) # don't join any channels if we're just doing a lag check if not lagcheck: channels.Main = channels.add(botconfig.CHANNEL, cli) channels.Dummy = channels.add("*", cli) if botconfig.ALT_CHANNELS: for chan in botconfig.ALT_CHANNELS.split(","): channels.add(chan, cli) if botconfig.DEV_CHANNEL: channels.Dev = channels.add(botconfig.DEV_CHANNEL, cli) if var.LOG_CHANNEL: channels.add(var.LOG_CHANNEL, cli) #if var.CHANSERV_OP_COMMAND: # TODO: Add somewhere else if needed # cli.msg(var.CHANSERV, var.CHANSERV_OP_COMMAND.format(channel=botconfig.CHANNEL)) users.Bot.change_nick(botconfig.NICK) if var.SERVER_PING_INTERVAL > 0: def ping_server_timer(cli): ping_server(cli) t = threading.Timer(var.SERVER_PING_INTERVAL, ping_server_timer, args=(cli, )) t.daemon = True t.start() ping_server_timer(cli) if lagcheck: cli.command_handler["privmsg"] = on_privmsg run_lagcheck(cli)
def chan_created(cli, server, bot_nick, chan, timestamp): """Update the channel timestamp with the server's information. Ordering and meaning of arguments for a bare MODE response end: 0 - The IRCClient instance (like everywhere else) 1 - The server the requester (i.e. the bot) is on 2 - The nickname of the requester (i.e. the bot) 3 - The channel in question 4 - The UNIX timestamp of when the channel was created We probably don't need to care about this at all, but it doesn't hurt to keep it around. If we ever need it, it will be there. """ channels.add(chan, cli).timestamp = int(timestamp)
def prepare_stuff(cli, prefix, *args): from src import lagcheck alog("Received end of MOTD from {0}".format(prefix)) # This callback only sets up event listeners wolfgame.connect_callback() # just in case we haven't managed to successfully auth yet if botconfig.PASS and not botconfig.SASL_AUTHENTICATION: cli.ns_identify(botconfig.USERNAME or botconfig.NICK, botconfig.PASS, nickserv=var.NICKSERV, command=var.NICKSERV_IDENTIFY_COMMAND) # don't join any channels if we're just doing a lag check if not lagcheck: channels.Main = channels.add(botconfig.CHANNEL, cli) channels.Dummy = channels.add("*", cli) if botconfig.ALT_CHANNELS: for chan in botconfig.ALT_CHANNELS.split(","): channels.add(chan, cli) if botconfig.DEV_CHANNEL: channels.Dev = channels.add(botconfig.DEV_CHANNEL, cli) if var.LOG_CHANNEL: channels.add(var.LOG_CHANNEL, cli) else: alog("Preparing lag check") # if we ARE doing a lagcheck, we need at least our own host or things break users.Bot.who() #if var.CHANSERV_OP_COMMAND: # TODO: Add somewhere else if needed # cli.msg(var.CHANSERV, var.CHANSERV_OP_COMMAND.format(channel=botconfig.CHANNEL)) users.Bot.change_nick(botconfig.NICK) if var.SERVER_PING_INTERVAL > 0: def ping_server_timer(cli): ping_server(cli) t = threading.Timer(var.SERVER_PING_INTERVAL, ping_server_timer, args=(cli,)) t.daemon = True t.start() ping_server_timer(cli)
def kicked_from_chan(cli, rawnick, chan, target, reason): """Handle a user being kicked from a channel. Ordering and meaning of arguments for a channel KICK: 0 - The IRCClient instance (like everywhere else) 1 - The raw nick (nick!ident@host) of the user performing the kick 2 - The channel the kick was performed on 3 - The target of the kick 4 - The reason given for the kick (always present) """ ch = channels.add(chan, cli) actor = users._get(rawnick, allow_none=True) # FIXME user = users._get(target) # FIXME Event("chan_kick", {}).dispatch(var, ch, actor, user, reason) if user is users.Bot: ch._clear() else: ch.remove_user(user)
def join_chan(cli, rawnick, chan, account=None, realname=None): """Handle a user joining a channel, which may be the bot itself. Ordering and meaning of arguments for a channel JOIN: 0 - The IRCClient instance (like everywhere else) 1 - The raw nick (nick!ident@host) of the user joining the channel 2 - The channel the user joined The following two arguments are optional and only present if the server supports the extended-join capability (we will have requested it when we connected if it was supported): 3 - The account the user is identified to, or "*" if none 4 - The realname (gecos) of the user, or "" if none """ if account == "*": account = None if realname == "": realname = None ch = channels.add(chan, cli) ch.state = channels._States.Joined user = users._add(cli, nick=rawnick, realname=realname, account=account) # FIXME ch.users.add(user) user.channels[ch] = set() # mark the user as here, in case they used to be connected before but left user.disconnected = False if user is users.Bot: ch.mode() ch.mode(Features["CHANMODES"][0]) ch.who() Event("chan_join", {}).dispatch(var, ch, user)
def join_chan(cli, rawnick, chan, account=None, realname=None): """Handle a user joining a channel, which may be the bot itself. Ordering and meaning of arguments for a channel JOIN: 0 - The IRCClient instance (like everywhere else) 1 - The raw nick (nick!ident@host) of the user joining the channel 2 - The channel the user joined The following two arguments are optional and only present if the server supports the extended-join capability (we will have requested it when we connected if it was supported): 3 - The account the user is identified to, or "*" if none 4 - The realname (gecos) of the user, or "" if none """ if account == "*": account = None if realname == "": realname = None ch = channels.add(chan, cli) ch.state = channels._States.Joined user = users._add(cli, nick=rawnick, realname=realname, account=account) # FIXME ch.users.add(user) user.channels[ch] = set() if user is users.Bot: ch.mode() ch.mode(Features["CHANMODES"][0]) ch.who() Event("chan_join", {}).dispatch(var, ch, user)
def part_chan(cli, rawnick, chan, reason=""): """Handle a user leaving a channel, which may be the bot itself. Ordering and meaning of arguments for a channel PART: 0 - The IRCClient instance (like everywhere else) 1 - The raw nick (nick!ident@host) of the user leaving the channel 2 - The channel being left The following argument may or may not be present: 3 - The reason the user gave for parting (if any) """ ch = channels.add(chan, cli) user = users._get(rawnick) # FIXME Event("chan_part", {}).dispatch(var, ch, user, reason) if user is users.Bot: # oh snap! we're no longer in the channel! ch._clear() else: ch.remove_user(user)
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. An extended WHO (WHOX) is caracterised by a second parameter to the request That parameter must be '%' followed by at least one of 'tcuihsnfdlar' If the 't' specifier is present, the specifiers must be followed by a comma and at most 3 bytes This is the ordering if all parameters are present, but not all of them are required If a parameter depends on a specifier, it will be stated at the front If a specifier is not given, the parameter will be omitted in the reply Ordering and meaning of arguments for an extended WHO (WHOX) response: 0 - - The IRCClient instance (like everywhere else) 1 - - The server the requester (i.e. the bot) is on 2 - - The nickname of the requester (i.e. the bot) 3 - t - The data sent alongside the request 4 - c - The channel the request was made on 5 - u - The ident of the user in this reply 6 - i - The IP address of the user in this reply 7 - h - The hostname of the user in this reply 8 - s - The server the user in this reply is on 9 - n - The nickname of the user in this reply 10 - f - Status (H = Not away, G = Away, * = IRC operator, @ = Opped in the channel in 5, + = Voiced in the channel in 5) 11 - d - The hop count 12 - l - The idle time (or 0 for users on other servers) 13 - a - The services account name (or 0 if none/not logged in) 14 - r - The realname (gecos) This fires off the "who_result" event, and dispatches it with three arguments, the game state namespace, a Channel, and a User. Less important attributes can be accessed via the event.params namespace. """ if account == "0": account = None hop = int(hop) idle = int(idle) is_away = ("G" in status) data = int.from_bytes(data.encode(Features["CHARSET"]), "little") modes = {Features["PREFIX"].get(s) for s in status} - {None} user = users._add(cli, nick=nick, ident=ident, host=host, realname=realname, account=account) # FIXME ch = None if not channels.predicate(chan): ch = channels.add(chan, cli) 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) 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())
def handle_endlistmode(cli, chan, mode): """Handle the end of a list mode listing.""" ch = channels.add(chan, cli) ch.queue("end_listmode", {}, (var, ch, mode))