Compare commits

...

5 Commits

13 changed files with 126 additions and 32 deletions

View File

@ -13,7 +13,7 @@ Usage
-----
This plugin constantly tries to take whatever nick is configured as
supybot.nick. Just make sure that's set appropriately, and thus plugin
supybot.nick. Just make sure that's set appropriately, and this plugin
will do the rest.
.. _conf-NickCapture:

View File

@ -31,7 +31,7 @@ msgstr ""
#: plugin.py:41
msgid ""
"This plugin constantly tries to take whatever nick is configured as\n"
" supybot.nick. Just make sure that's set appropriately, and thus plugin\n"
" supybot.nick. Just make sure that's set appropriately, and this plugin\n"
" will do the rest."
msgstr ""
"Dieses Plugin versucht dauernd den Nick der in supybot.nick konfiguriert ist "

View File

@ -34,7 +34,7 @@ msgstr ""
#: plugin.py:41
msgid ""
"This plugin constantly tries to take whatever nick is configured as\n"
" supybot.nick. Just make sure that's set appropriately, and thus plugin\n"
" supybot.nick. Just make sure that's set appropriately, and this plugin\n"
" will do the rest."
msgstr ""
"Tämä lisäosa yrittää jatkuvasti ottaa sen nimimerkin, joka on määritetty\n"

View File

@ -32,7 +32,7 @@ msgstr ""
#: plugin.py:41
msgid ""
"This plugin constantly tries to take whatever nick is configured as\n"
" supybot.nick. Just make sure that's set appropriately, and thus plugin\n"
" supybot.nick. Just make sure that's set appropriately, and this plugin\n"
" will do the rest."
msgstr ""
"Ce plugin essaye constament de récupérer le nick configuré dans supybot."

View File

@ -28,7 +28,7 @@ msgstr ""
#: plugin.py:41
msgid ""
"This plugin constantly tries to take whatever nick is configured as\n"
" supybot.nick. Just make sure that's set appropriately, and thus plugin\n"
" supybot.nick. Just make sure that's set appropriately, and this plugin\n"
" will do the rest."
msgstr ""
"Questo plugin cerca costantemente di ottenere qualsiasi nick sia impostato\n"

View File

@ -31,7 +31,7 @@ msgstr ""
#, docstring
msgid ""
"This plugin constantly tries to take whatever nick is configured as\n"
" supybot.nick. Just make sure that's set appropriately, and thus plugin\n"
" supybot.nick. Just make sure that's set appropriately, and this plugin\n"
" will do the rest."
msgstr ""

View File

@ -39,7 +39,7 @@ _ = PluginInternationalization('NickCapture')
class NickCapture(callbacks.Plugin):
"""This plugin constantly tries to take whatever nick is configured as
supybot.nick. Just make sure that's set appropriately, and thus plugin
supybot.nick. Just make sure that's set appropriately, and this plugin
will do the rest."""
public = False
def __init__(self, irc):

View File

@ -195,9 +195,14 @@ class Seen(callbacks.Plugin):
if len(results) == 1:
(nick, info) = results[0]
(when, said) = info
reply = format(_('%s was last seen in %s %s ago'),
nick, channel,
utils.timeElapsed(time.time()-when))
if nick in irc.state.channels[channel].users:
reply = format(_('%s was last seen in %s %s ago, and is in the channel now'),
nick, channel,
utils.timeElapsed(time.time()-when))
else:
reply = format(_('%s was last seen in %s %s ago'),
nick, channel,
utils.timeElapsed(time.time()-when))
if self.registryValue('showLastMessage', channel, irc.network):
if minisix.PY2:
said = said.decode('utf8')
@ -207,13 +212,20 @@ class Seen(callbacks.Plugin):
L = []
for (nick, info) in results:
(when, said) = info
L.append(format(_('%s (%s ago)'), nick,
utils.timeElapsed(time.time()-when)))
if nick in irc.state.channels[channel].users:
L.append(format(_('%s (%s ago, and is in the channel now)'), nick,
utils.timeElapsed(time.time()-when)))
else:
L.append(format(_('%s (%s ago)'), nick,
utils.timeElapsed(time.time()-when)))
irc.reply(format(_('%s could be %L'), name, (L, _('or'))))
else:
irc.reply(format(_('I haven\'t seen anyone matching %s.'), name))
except KeyError:
irc.reply(format(_('I have not seen %s.'), name))
if name in irc.state.channels[channel].users:
irc.reply(format(_("%s is in the channel right now."), name))
else:
irc.reply(format(_('I have not seen %s.'), name))
def _checkChannelPresence(self, irc, channel, target, you):
if channel not in irc.state.channels:
@ -277,8 +289,13 @@ class Seen(callbacks.Plugin):
db = self.db
try:
(when, said) = db.seen(channel, '<last>')
reply = format(_('Someone was last seen in %s %s ago'),
channel, utils.timeElapsed(time.time()-when))
pattern = r'<(.*?)>'
match = re.search(pattern, said)
if not match:
irc.error(format(_('I couldn\'t parse the nick of the speaker of the last line.')), Raise=True)
nick = match.group(1)
reply = format(_('Last seen in %s was %s, %s ago'),
channel, nick, utils.timeElapsed(time.time()-when))
if self.registryValue('showLastMessage', channel, irc.network):
reply = _('%s: %s') % (reply, said)
irc.reply(reply)
@ -303,14 +320,22 @@ class Seen(callbacks.Plugin):
db = self.db
try:
(when, said) = db.seen(channel, user.id)
reply = format(_('%s was last seen in %s %s ago'),
user.name, channel,
utils.timeElapsed(time.time()-when))
if user.name in irc.state.channels[channel].users:
reply = format(_('%s was last seen in %s %s ago and is in the channel now'),
user.name, channel,
utils.timeElapsed(time.time()-when))
else:
reply = format(_('%s was last seen in %s %s ago'),
user.name, channel,
utils.timeElapsed(time.time()-when))
if self.registryValue('showLastMessage', channel, irc.network):
reply = _('%s: %s') % (reply, said)
irc.reply(reply)
except KeyError:
irc.reply(format(_('I have not seen %s.'), user.name))
if user.name in irc.state.channels[channel].users:
irc.reply(format(_("%s is in the channel right now."), user.name))
else:
irc.reply(format(_('I have not seen %s.'), user.name))
@internationalizeDocstring
def user(self, irc, msg, args, channel, user):

View File

@ -83,12 +83,10 @@ class ChannelDBTestCase(ChannelPluginTestCase):
self.assertNotError('seen last')
self.assertNotError('list')
self.assertNotError('config plugins.Seen.minimumNonWildcard 2')
self.assertError('seen *')
self.assertNotError('seen %s' % self.nick)
m = self.assertNotError('seen %s' % self.nick.upper())
self.assertIn(self.nick.upper(), m.args[1])
self.assertRegexp('seen user %s' % self.nick,
'^%s was last seen' % self.nick)
self.assertError('seen *')
self.assertNotError('seen %s' % self.nick)
self.assertNotError('config plugins.Seen.minimumNonWildcard 0')
orig = conf.supybot.protocols.irc.strictRfc()
try:
@ -101,6 +99,28 @@ class ChannelDBTestCase(ChannelPluginTestCase):
finally:
conf.supybot.protocols.irc.strictRfc.setValue(orig)
def testSeenNickInChannel(self):
# Test case: 'seen' with a nick (user in channel)
self.irc.feedMsg(ircmsgs.join(self.channel, self.irc.nick,
prefix=self.prefix))
self.assertRegexp('seen %s' % self.nick, 'is in the channel right now')
m = self.assertNotError('seen %s' % self.nick.upper())
self.assertIn(self.nick.upper(), m.args[1])
def testSeenUserInChannel(self):
# Test case: 'seen' with a user (user in channel)
self.irc.feedMsg(ircmsgs.join(self.channel, self.irc.nick,
prefix=self.prefix))
self.assertRegexp('seen user %s' % self.nick, 'is in the channel right now')
def testSeenNickNotInChannel(self):
# Test case: 'seen' with a nick (user not in channel)
testnick = "user123"
self.irc.feedMsg(ircmsgs.join(self.channel, testnick, "user123!baz"))
self.irc.feedMsg(ircmsgs.part(self.channel, prefix="user123!baz"))
self.assertNotRegexp("seen %s" % testnick, "is in the channel right now")
def testSeenNoUser(self):
self.irc.feedMsg(ircmsgs.join(self.channel, self.irc.nick,
prefix=self.prefix))

View File

@ -76,17 +76,53 @@ class Status(callbacks.Plugin):
Returns the status of the bot.
"""
# Initialize dictionaries
nicks = {}
networks = {}
# Iterate through each IRC network
for Irc in world.ircs:
networks.setdefault(Irc.network, []).append(Irc.nick)
networks = sorted(networks.items())
networks = [format(_('%s as %L'), net, nicks) for (net,nicks) in networks]
L = [format(_('I am connected to %L.'), networks)]
network_name = Irc.network
channels = Irc.state.channels
# Initialize counts for this network
channel_counts = len(channels)
op_counts = sum(1 for channel in channels.values() if Irc.nick in channel.ops)
halfop_counts = sum(1 for channel in channels.values() if Irc.nick in channel.halfops)
voice_counts = sum(1 for channel in channels.values() if Irc.nick in channel.voices)
normal_counts = sum(1 for channel in channels.values() if Irc.nick in channel.users)
# Store the counts in dictionaries
nicks[network_name] = Irc.nick
networks[network_name] = {
'Channels': channel_counts,
'Ops': op_counts,
'Half-Ops': halfop_counts,
'Voiced': voice_counts,
'Regular': normal_counts
}
# Prepare the response
response_lines = []
for network_name, counts in networks.items():
response_lines.append(
format(
_('I am connected to %s as %s: Channels: %s, Ops: %s, Half-Ops: %s, Voiced: %s, Regular: %s'),
network_name,
nicks[network_name],
counts['Channels'],
counts['Ops'],
counts['Half-Ops'],
counts['Voiced'],
counts['Regular']
)
)
if world.profiling:
L.append(_('I am currently in code profiling mode.'))
irc.reply(' '.join(L))
response_lines.append(_('I am currently in code profiling mode.'))
response = format(_("%L"), response_lines)
irc.reply(response)
status = wrap(status)
@internationalizeDocstring
def threads(self, irc, msg, args):
"""takes no arguments

View File

@ -136,8 +136,8 @@ def _addressed(irc, msg, prefixChars=None, nicks=None,
continue
except ValueError: # split didn't work.
continue
elif whenAddressedByNickAtEnd and lowered.endswith(nick):
rest = payload[:-len(nick)]
elif whenAddressedByNickAtEnd and lowered.rstrip().endswith(nick):
rest = payload.rstrip()[:-len(nick)]
possiblePayload = rest.rstrip(' \t,;')
if possiblePayload != rest:
# There should be some separator between the nick and the

View File

@ -200,6 +200,13 @@ class SocketDriver(drivers.IrcDriver, drivers.ServersMixin):
"""Called by _select() when we can read data."""
try:
new_data = self.conn.recv(1024)
if hasattr(self.conn, "pending") and self.conn.pending():
# This is a TLS socket and there are decrypted bytes in the
# buffer. We need to read them now, or we would not get them
# until the next time select() returns this socket (which may
# be in a very long time, as select() does not know recv() on
# the TLS wrapper would not block).
new_data += self.conn.recv(self.conn.pending())
if not new_data:
# Socket was closed
self._handleSocketError(None)

View File

@ -272,6 +272,12 @@ class FunctionsTestCase(SupyTestCase):
self.assertEqual(callbacks.addressed('bar', msg,
whenAddressedByNickAtEnd=True),
'baz')
# Test that it still works with trailing whitespace:
msg = ircmsgs.privmsg('#foo', 'baz, bar \t')
self.assertEqual(callbacks.addressed('bar', msg,
whenAddressedByNickAtEnd=True),
'baz')
def testAddressedPrefixCharsTakePrecedenceOverNickAtEnd(self):
irc = getTestIrc()