diff --git a/sopel/bot.py b/sopel/bot.py index 9608fdf7fd..64256ec656 100644 --- a/sopel/bot.py +++ b/sopel/bot.py @@ -270,7 +270,7 @@ def call(self, func, sopel, trigger): def dispatch(self, pretrigger): args = pretrigger.args - event, args, text = pretrigger.event, args, args[-1] + event, args, text = pretrigger.event, args, args[-1] if args else '' if self.config.core.nick_blocks or self.config.core.host_blocks: nick_blocked = self._nick_blocked(pretrigger.nick) diff --git a/sopel/coretasks.py b/sopel/coretasks.py index c4087cadef..4ace78d47a 100644 --- a/sopel/coretasks.py +++ b/sopel/coretasks.py @@ -288,13 +288,16 @@ def _remove_from_channel(bot, nick, channel): bot.users.pop(nick, None) -def _accounts_enabled(bot): - return ('account-notify' in bot.enabled_capabilities and - 'extended-join' in bot.enabled_capabilities) +def _whox_enabled(bot): + # Either privilege tracking or away notification. For simplicity, both + # account notify and extended join must be there for account tracking. + return (('account-notify' in bot.enabled_capabilities and + 'extended-join' in bot.enabled_capabilities) or + 'away-notify' in bot.enabled_capabilities) def _send_who(bot, channel): - if _accounts_enabled(bot): + if _whox_enabled(bot): # WHOX syntax, see http://faerion.sourceforge.net/doc/irc/whox.var # Needed for accounts in who replies. The random integer is a param # to identify the reply as one from this command, because if someone @@ -303,7 +306,7 @@ def _send_who(bot, channel): while rand in who_reqs: rand = str(randint(0, 999)) who_reqs[rand] = channel - bot.write(['WHO', channel, 'a%nuacht,' + rand]) + bot.write(['WHO', channel, 'a%nuachtf,' + rand]) else: # We might be on an old network, but we still care about keeping our # user list updated @@ -330,7 +333,9 @@ def track_join(bot, trigger): user = User(trigger.nick, trigger.user, trigger.host) bot.channels_[trigger.sender].add_user(user) - if len(trigger.args) > 1 and trigger.args[1] != '*' and _accounts_enabled(bot): + if len(trigger.args) > 1 and trigger.args[1] != '*' and ( + 'account-notify' in bot.enabled_capabilities and + 'extended-join' in bot.enabled_capabilities): user.account = trigger.args[1] @@ -409,6 +414,8 @@ def acct_warn(bot, cap): bot._cap_reqs['account-notify'] = (['', 'coretasks', None, acct_warn],) if 'extended-join' not in bot._cap_reqs: bot._cap_reqs['extended-join'] = (['', 'coretasks', None, acct_warn],) + if 'away-notify' not in bot._cap_reqs: + bot._cap_reqs['away-notify'] = (['', 'coretasks', None, None],) for cap, reqs in iteritems(bot._cap_reqs): # At this point, we know mandatory and prohibited don't co-exist, but @@ -574,17 +581,18 @@ def account_notify(bot, trigger): @sopel.module.priority('high') @sopel.module.unblockable def recv_whox(bot, trigger): - if (len(trigger.args) < 2 or trigger.args[1] not in who_reqs or - not _accounts_enabled(bot)): + print(trigger.args) + if len(trigger.args) < 2 or trigger.args[1] not in who_reqs: # Ignored, some module probably called WHO return - if len(trigger.args) != 7: + if len(trigger.args) != 8: return LOGGER.warning('While populating `bot.accounts` a WHO response was malformed.') - _, _, channel, user, host, nick, account = trigger.args - _record_who(bot, channel, user, host, nick, account) + _, _, channel, user, host, nick, status, account = trigger.args + away = 'G' in status + _record_who(bot, channel, user, host, nick, account, away) -def _record_who(bot, channel, user, host, nick, account=None): +def _record_who(bot, channel, user, host, nick, account=None, away=None): nick = Identifier(nick) channel = Identifier(channel) if nick not in bot.users: @@ -594,6 +602,7 @@ def _record_who(bot, channel, user, host, nick, account=None): user.account = None else: user.account = account + user.away = away if channel not in bot.channels_: bot.channels_[channel] = Channel(channel) bot.channels_[channel].add_user(user) @@ -613,5 +622,17 @@ def recv_who(bot, trigger): @sopel.module.priority('high') @sopel.module.unblockable def end_who(bot, trigger): - if _accounts_enabled(bot): + if _whox_enabled(bot): who_reqs.pop(trigger.args[1], None) + + +@sopel.module.rule('.*') +@sopel.module.event('AWAY') +@sopel.module.priority('high') +@sopel.module.thread(False) +@sopel.module.unblockable +def track_notify(bot, trigger): + if trigger.nick not in bot.users: + bot.users[trigger.nick] = User(trigger.nick, trigger.user, trigger.host) + user = bot.users[trigger.nick] + user.away = bool(trigger.args) diff --git a/sopel/tools/target.py b/sopel/tools/target.py index 65289a0079..e3626648b5 100644 --- a/sopel/tools/target.py +++ b/sopel/tools/target.py @@ -13,6 +13,8 @@ def __init__(self, nick, user, host): self.user = user self.host = host self.channels = {} + self.account = None + self.away = None hostmask = property(lambda self: '{}!{}@{}'.format(self.nick, self.user, self.host)) diff --git a/sopel/trigger.py b/sopel/trigger.py index ef3049335d..766ef4dd36 100644 --- a/sopel/trigger.py +++ b/sopel/trigger.py @@ -131,10 +131,10 @@ class Trigger(unicode): """True if the nick which triggered the command is the bot's owner.""" def __new__(cls, config, message, match): - self = unicode.__new__(cls, message.args[-1]) + self = unicode.__new__(cls, message.args[-1] if message.args else '') self._pretrigger = message self._match = match - self._is_privmsg = message.sender.is_nick() + self._is_privmsg = message.sender and message.sender.is_nick() def match_host_or_nick(pattern): pattern = sopel.tools.get_hostmask_regex(pattern)