diff --git a/sopel_modules/SpiceBot/Channels.py b/sopel_modules/SpiceBot/Channels.py index 52b67bb..160cd25 100644 --- a/sopel_modules/SpiceBot/Channels.py +++ b/sopel_modules/SpiceBot/Channels.py @@ -26,7 +26,7 @@ class BotChannels(): """This Logs all channels known to the server""" def __init__(self): self.setup_channels() - + self.who_reqs = {} self.lock = threading.Lock() self.channel_lock = False self.channels = [] @@ -254,6 +254,38 @@ class BotChannels(): def mode(self, bot, trigger): return + def rpl_names(self, bot, trigger): + """Handle NAMES response, happens when joining to channels.""" + names = trigger.split() + + # TODO specific to one channel type. See issue 281. + channels = re.search(r'(#\S*)', trigger.raw) + if not channels: + return + channel = Identifier(channels.group(1)) + self.add_channel(channel) + + mapping = {'+': sopel.module.VOICE, + '%': sopel.module.HALFOP, + '@': sopel.module.OP, + '&': sopel.module.ADMIN, + '~': sopel.module.OWNER} + + for name in names: + nick = Identifier(name.lstrip(''.join(mapping.keys()))) + self.add_to_channel(channel, nick) + + def rpl_who(self, bot, trigger): + if len(trigger.args) < 2 or trigger.args[1] not in self.who_reqs: + # Ignored, some module probably called WHO + return + if len(trigger.args) != 8: + return + _, _, channel, user, host, nick, status, account = trigger.args + nick = Identifier(nick) + channel = Identifier(channel) + self.add_to_channel(channel, nick) + def check_channel_bot(self, channel, allchan=False): if str(channel).lower() in self.channels: return True diff --git a/sopel_modules/SpiceBot/Events.py b/sopel_modules/SpiceBot/Events.py index cc72902..ac5cfc5 100644 --- a/sopel_modules/SpiceBot/Events.py +++ b/sopel_modules/SpiceBot/Events.py @@ -35,6 +35,8 @@ class BotEvents(object): def __init__(self): self.lock = threading.Lock() self.RPL_WELCOME = '001' # This is a defined IRC event + self.RPL_NAMREPLY = '353' # This is a defined IRC event + self.RPL_WHOREPLY = '352' # This is a defined IRC event self.BOT_UPTIME = time.time() self.BOT_WELCOME = '1001' self.BOT_READY = '1002' diff --git a/sopel_modules/SpiceBot/Users.py b/sopel_modules/SpiceBot/Users.py index 4c6fff9..b51e900 100644 --- a/sopel_modules/SpiceBot/Users.py +++ b/sopel_modules/SpiceBot/Users.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals, absolute_import, division, print_function """A way to track users""" +import sopel from sopel.tools import Identifier from .Database import db as botdb @@ -10,6 +11,7 @@ from .Tools import is_number, inlist, similar, array_arrangesort import spicemanip import threading +import re # TODO timestamp for new .seen @@ -261,6 +263,83 @@ class BotUsers(): def mode(self, bot, trigger): return + def rpl_names(self, bot, trigger): + """Handle NAMES response, happens when joining to channels.""" + names = trigger.split() + + # TODO specific to one channel type. See issue 281. + channels = re.search(r'(#\S*)', trigger.raw) + if not channels: + return + channel = Identifier(channels.group(1)) + + mapping = {'+': sopel.module.VOICE, + '%': sopel.module.HALFOP, + '@': sopel.module.OP, + '&': sopel.module.ADMIN, + '~': sopel.module.OWNER} + + for name in names: + nick = Identifier(name.lstrip(''.join(mapping.keys()))) + # Identify + nick_id = self.whois_ident(nick) + # Verify nick is in the all list + self.add_to_all(nick, nick_id) + # Verify nick is in the all list + self.add_to_current(nick, nick_id) + # set current nick + self.mark_current_nick(nick, nick_id) + # add joined channel to nick list + self.add_channel(channel, nick_id) + # mark user as online + self.mark_user_online(nick_id) + + def rpl_who(self, bot, trigger): + if len(trigger.args) < 2 or trigger.args[1] not in self.who_reqs: + # Ignored, some module probably called WHO + return + if len(trigger.args) != 8: + return + _, _, channel, user, host, nick, status, account = trigger.args + nick = Identifier(nick) + channel = Identifier(channel) + # Identify + nick_id = self.whois_ident(nick) + # Verify nick is in the all list + self.add_to_all(nick, nick_id) + # Verify nick is in the all list + self.add_to_current(nick, nick_id) + # set current nick + self.mark_current_nick(nick, nick_id) + # add joined channel to nick list + self.add_channel(channel, nick_id) + # mark user as online + self.mark_user_online(nick_id) + + def account(self, bot, trigger): + # Identify + nick_id = self.whois_ident(trigger.nick) + # Verify nick is in the all list + self.add_to_all(trigger.nick, nick_id) + # Verify nick is in the all list + self.add_to_current(trigger.nick, nick_id) + # set current nick + self.mark_current_nick(trigger.nick, nick_id) + # mark user as online + self.mark_user_online(nick_id) + + def track_notify(self, bot, trigger): + # Identify + nick_id = self.whois_ident(trigger.nick) + # Verify nick is in the all list + self.add_to_all(trigger.nick, nick_id) + # Verify nick is in the all list + self.add_to_current(trigger.nick, nick_id) + # set current nick + self.mark_current_nick(trigger.nick, nick_id) + # mark user as online + self.mark_user_online(nick_id) + def nick_actual(self, nick, altlist=None): nick_id = self.whois_ident(nick) nick_actual = self.ID(nick_id) diff --git a/sopel_modules/SpiceBot_Core_Processing/Channels.py b/sopel_modules/SpiceBot_Core_Processing/Channels.py index 6cdb2d9..94d34c4 100644 --- a/sopel_modules/SpiceBot_Core_Processing/Channels.py +++ b/sopel_modules/SpiceBot_Core_Processing/Channels.py @@ -139,3 +139,17 @@ def channels_users_mode(bot, trigger): def bot_channelscan(bot, trigger): while True: SpiceBot.channels.channel_scan(bot) + + +@sopel.module.event(SpiceBot.events.RPL_NAMREPLY) +@sopel.module.rule('(.*)') +def handle_names(bot, trigger): + SpiceBot.channels.rpl_names(bot, trigger) + + +@sopel.module.event(SpiceBot.events.RPL_WHOREPLY) +@sopel.module.rule('.*') +@sopel.module.priority('high') +@sopel.module.unblockable +def recv_who(bot, trigger): + SpiceBot.channels.rpl_who(bot, trigger) diff --git a/sopel_modules/SpiceBot_Core_Processing/Users.py b/sopel_modules/SpiceBot_Core_Processing/Users.py index 3082c9e..d97fa11 100644 --- a/sopel_modules/SpiceBot_Core_Processing/Users.py +++ b/sopel_modules/SpiceBot_Core_Processing/Users.py @@ -54,3 +54,29 @@ def bot_channelscan_users(bot, trigger): @sopel.module.rule('.*') def bot_users_chat(bot, trigger): SpiceBot.users.chat(bot, trigger) + + +@sopel.module.event(SpiceBot.events.RPL_NAMREPLY) +@sopel.module.rule('(.*)') +def handle_names(bot, trigger): + SpiceBot.users.rpl_names(bot, trigger) + + +@sopel.module.event(SpiceBot.events.RPL_WHOREPLY) +@sopel.module.rule('.*') +@sopel.module.priority('high') +@sopel.module.unblockable +def recv_who(bot, trigger): + SpiceBot.users.rpl_who(bot, trigger) + + +@sopel.module.event('ACCOUNT') +@sopel.module.rule('.*') +def account_notify(bot, trigger): + SpiceBot.users.account(bot, trigger) + + +@sopel.module.event('AWAY') +@sopel.module.rule('.*') +def track_notify(bot, trigger): + SpiceBot.users.track_notify(bot, trigger)