NickCapture & core: Add support for MONITOR. Closes GH-842.

This commit is contained in:
Valentin Lorentz 2015-05-15 19:24:24 +02:00
parent ba495f5719
commit 59d542bb70
3 changed files with 69 additions and 1 deletions

View File

@ -45,6 +45,12 @@ class NickCapture(callbacks.Plugin):
self.__parent = super(NickCapture, self)
self.__parent.__init__(irc)
self.lastIson = 0
self.monitoring = []
def die(self):
for irc in self.monitoring:
nick = self._getNick(irc.network)
irc.unmonitor(nick)
def _getNick(self, network):
network_nick = conf.supybot.networks.get(network).nick()
@ -60,10 +66,16 @@ class NickCapture(callbacks.Plugin):
# We used to check this, but nicksToHostmasks is never cleared
# except on reconnects, which can cause trouble.
# if nick not in irc.state.nicksToHostmasks:
self._ison(irc, nick)
if 'monitor' in irc.state.supported:
if irc not in self.monitoring:
irc.monitor(nick)
self.monitoring.append(irc)
else:
self._ison(irc, nick)
self.__parent.__call__(irc, msg)
def _ison(self, irc, nick):
assert 'monitor' not in irc.state.supported
if self.registryValue('ison'):
now = time.time()
if now - self.lastIson > self.registryValue('ison.period'):
@ -95,6 +107,16 @@ class NickCapture(callbacks.Plugin):
nick = self._getNick(irc.network)
if nick:
self._sendNick(irc, nick)
def do731(self, irc, msg):
"""This is sent by the MONITOR when a nick goes offline."""
nick = self._getNick(irc.network)
for target in msg.args[1].split(','):
if nick == target:
self._sendNick(irc, nick)
self.monitoring.remove(irc)
irc.unmonitor(nick)
break
NickCapture = internationalizeDocstring(NickCapture)
Class = NickCapture

View File

@ -666,6 +666,7 @@ class Irc(IrcCommandDispatcher):
self._setNonResettingVariables()
self._queueConnectMessages()
self.startedSync = ircutils.IrcDict()
self.monitoring = ircutils.IrcDict()
def isChannel(self, s):
"""Helper function to check whether a given string is a channel on
@ -1041,6 +1042,38 @@ class Irc(IrcCommandDispatcher):
command='CAP',
args=('END',)))
def monitor(self, targets):
"""Increment a counter of how many callbacks monitor each target;
and send a MONITOR + to the server if the target is not yet
monitored."""
if isinstance(targets, str):
targets = [targets]
not_yet_monitored = set()
for target in targets:
if target in self.monitoring:
self.monitoring[target] += 1
else:
not_yet_monitored.add(target)
self.monitoring[target] = 1
if not_yet_monitored:
self.queueMsg(ircmsgs.monitor('+', not_yet_monitored))
return not_yet_monitored
def unmonitor(self, targets):
"""Decrements a counter of how many callbacks monitor each target;
and send a MONITOR - to the server if the counter drops to 0."""
if isinstance(targets, str):
targets = [targets]
should_be_unmonitored = set()
for target in targets:
self.monitoring[target] -= 1
if self.monitoring[target] == 0:
del self.monitoring[target]
should_be_unmonitored.add(target)
if should_be_unmonitored:
self.queueMsg(ircmsgs.monitor('-', should_be_unmonitored))
return should_be_unmonitored
def do903(self, msg):
log.info('%s: SASL authentication successful', self.network)
self.queueMsg(ircmsgs.IrcMsg(command='CAP', args=('END',)))

View File

@ -855,6 +855,19 @@ def ison(nick, prefix='', msg=None):
prefix = msg.prefix
return IrcMsg(prefix=prefix, command='ISON', args=(nick,), msg=msg)
def monitor(subcommand, nicks=None, prefix='', msg=None):
if conf.supybot.protocols.irc.strictRfc():
assert isNick(nick), repr(nick)
assert subcommand in '+-CLS'
if subcommand in 'CLS':
assert nicks is None
if msg and not prefix:
prefix = msg.prefix
if not isinstance(nicks, str):
nicks = ','.join(nicks)
return IrcMsg(prefix=prefix, command='MONITOR', args=(subcommand, nicks),
msg=msg)
def error(s, msg=None):
return IrcMsg(command='ERROR', args=(s,), msg=msg)