mirror of
https://github.com/Mikaela/Limnoria.git
synced 2024-12-27 21:22:39 +01:00
Merge remote-tracking branch 'supybot/master' into testing
Conflicts: .mailmap README docs/FAQ.rst plugins/Ctcp/plugin.py plugins/Misc/plugin.py plugins/Network/plugin.py plugins/QuoteGrabs/plugin.py plugins/RSS/README.txt plugins/Relay/plugin.py plugins/ShrinkUrl/config.py plugins/ShrinkUrl/plugin.py plugins/ShrinkUrl/test.py setup.py src/callbacks.py src/commands.py src/conf.py test/test_commands.py
This commit is contained in:
commit
487f8c8af5
@ -56,8 +56,8 @@ class Admin(callbacks.Plugin):
|
||||
def do437(self, irc, msg):
|
||||
"""Nick/channel temporarily unavailable."""
|
||||
target = msg.args[0]
|
||||
t = time.time() + 30
|
||||
if irc.isChannel(target): # We don't care about nicks.
|
||||
t = time.time() + 30
|
||||
# Let's schedule a rejoin.
|
||||
networkGroup = conf.supybot.networks.get(irc.network)
|
||||
def rejoin():
|
||||
@ -67,6 +67,16 @@ class Admin(callbacks.Plugin):
|
||||
schedule.addEvent(rejoin, t)
|
||||
self.log.info('Scheduling a rejoin to %s at %s; '
|
||||
'Channel temporarily unavailable.', target, t)
|
||||
else:
|
||||
irc = self.pendingNickChanges.get(irc, None)
|
||||
if irc is not None:
|
||||
def nick():
|
||||
irc.queueMsg(ircmsgs.nick(target))
|
||||
schedule.addEvent(nick, t)
|
||||
self.log.info('Scheduling a nick change to %s at %s; '
|
||||
'Nick temporarily unavailable.', target, t)
|
||||
else:
|
||||
self.log.debug('Got 437 without Admin.nick being called.')
|
||||
|
||||
def do471(self, irc, msg):
|
||||
try:
|
||||
|
@ -1,6 +1,6 @@
|
||||
###
|
||||
# Copyright (c) 2002-2004, Jeremiah Fincher
|
||||
# Copyright (c) 2010, James McCoy
|
||||
# Copyright (c) 2010,2015 James McCoy
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
@ -185,99 +185,10 @@ class Network(callbacks.Plugin):
|
||||
if (irc, loweredNick) not in self._whois:
|
||||
return
|
||||
(replyIrc, replyMsg, d, command) = self._whois[(irc, loweredNick)]
|
||||
START_CODE = '311' if command == 'whois' else '314'
|
||||
hostmask = '@'.join(d[START_CODE].args[2:4])
|
||||
user = d[START_CODE].args[-1]
|
||||
if '319' in d:
|
||||
channels = []
|
||||
for msg in d['319']:
|
||||
channels.extend(msg.args[-1].split())
|
||||
ops = []
|
||||
voices = []
|
||||
normal = []
|
||||
halfops = []
|
||||
for channel in channels:
|
||||
origchan = channel
|
||||
channel = channel.lstrip('@%+~!')
|
||||
# UnrealIRCd uses & for user modes and disallows it as a
|
||||
# channel-prefix, flying in the face of the RFC. Have to
|
||||
# handle this specially when processing WHOIS response.
|
||||
testchan = channel.lstrip('&')
|
||||
if testchan != channel and irc.isChannel(testchan):
|
||||
channel = testchan
|
||||
diff = len(channel) - len(origchan)
|
||||
modes = origchan[:diff]
|
||||
chan = irc.state.channels.get(channel)
|
||||
# The user is in a channel the bot is in, so the ircd may have
|
||||
# responded with otherwise private data.
|
||||
if chan:
|
||||
# Skip channels the caller isn't in. This prevents
|
||||
# us from leaking information when the channel is +s or the
|
||||
# target is +i.
|
||||
if replyMsg.nick not in chan.users:
|
||||
continue
|
||||
# Skip +s channels the target is in only if the reply isn't
|
||||
# being sent to that channel.
|
||||
if 's' in chan.modes and \
|
||||
not ircutils.strEqual(replyMsg.args[0], channel):
|
||||
continue
|
||||
if not modes:
|
||||
normal.append(channel)
|
||||
elif utils.iter.any(lambda c: c in modes,('@', '&', '~', '!')):
|
||||
ops.append(channel)
|
||||
elif utils.iter.any(lambda c: c in modes, ('%',)):
|
||||
halfops.append(channel)
|
||||
elif utils.iter.any(lambda c: c in modes, ('+',)):
|
||||
voices.append(channel)
|
||||
L = []
|
||||
if ops:
|
||||
L.append(format(_('is an op on %L'), ops))
|
||||
if halfops:
|
||||
L.append(format(_('is a halfop on %L'), halfops))
|
||||
if voices:
|
||||
L.append(format(_('is voiced on %L'), voices))
|
||||
if normal:
|
||||
if L:
|
||||
L.append(format(_('is also on %L'), normal))
|
||||
else:
|
||||
L.append(format(_('is on %L'), normal))
|
||||
else:
|
||||
if command == 'whois':
|
||||
L = [_('isn\'t on any publicly visible channels')]
|
||||
else:
|
||||
L = []
|
||||
channels = format('%L', L)
|
||||
if '317' in d:
|
||||
idle = utils.timeElapsed(d['317'].args[2])
|
||||
signon = time.strftime(conf.supybot.reply.format.time(),
|
||||
time.localtime(float(d['317'].args[3])))
|
||||
else:
|
||||
idle = _('<unknown>')
|
||||
signon = _('<unknown>')
|
||||
if '312' in d:
|
||||
server = d['312'].args[2]
|
||||
if len(d['312']) > 3:
|
||||
signoff = d['312'].args[3]
|
||||
else:
|
||||
server = _('<unknown>')
|
||||
if '301' in d:
|
||||
away = ' %s is away: %s.' % (nick, d['301'].args[2])
|
||||
else:
|
||||
away = ''
|
||||
if '320' in d:
|
||||
if d['320'].args[2]:
|
||||
identify = _(' identified')
|
||||
else:
|
||||
identify = ''
|
||||
else:
|
||||
identify = ''
|
||||
if command == 'whois':
|
||||
s = _('%s (%s) has been%s on server %s since %s (idle for %s). %s '
|
||||
'%s.%s') % (user, hostmask, identify, server,
|
||||
signon, idle, nick, channels, away)
|
||||
else:
|
||||
s = _('%s (%s) has been%s on server %s and disconnected on %s.') % \
|
||||
(user, hostmask, identify, server, signoff)
|
||||
d['318'] = msg
|
||||
s = ircutils.formatWhois(irc, d, caller=replyMsg.nick,
|
||||
channel=replyMsg.args[0],
|
||||
command=command)
|
||||
replyIrc.reply(s)
|
||||
del self._whois[(irc, loweredNick)]
|
||||
do369 = do318
|
||||
|
@ -279,7 +279,7 @@ class QuoteGrabs(callbacks.Plugin):
|
||||
# opposed to channel which is used to determine which db to store the
|
||||
# quote in
|
||||
chan = msg.args[0]
|
||||
if chan is None or not ircutils.isChannel(chan):
|
||||
if chan is None or not irc.isChannel(chan):
|
||||
raise callbacks.ArgumentError
|
||||
if ircutils.nickEqual(nick, msg.nick):
|
||||
irc.error(_('You can\'t quote grab yourself.'), Raise=True)
|
||||
|
@ -1,6 +1,6 @@
|
||||
###
|
||||
# Copyright (c) 2002-2004, Jeremiah Fincher
|
||||
# Copyright (c) 2010, James McCoy
|
||||
# Copyright (c) 2010,2015 James McCoy
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
@ -202,64 +202,9 @@ class Relay(callbacks.Plugin):
|
||||
if (irc, loweredNick) not in self._whois:
|
||||
return
|
||||
(replyIrc, replyMsg, d) = self._whois[(irc, loweredNick)]
|
||||
hostmask = '@'.join(d['311'].args[2:4])
|
||||
user = d['311'].args[-1]
|
||||
if '319' in d:
|
||||
channels = d['319'].args[-1].split()
|
||||
ops = []
|
||||
voices = []
|
||||
normal = []
|
||||
halfops = []
|
||||
for channel in channels:
|
||||
if channel.startswith('@'):
|
||||
ops.append(channel[1:])
|
||||
elif channel.startswith('%'):
|
||||
halfops.append(channel[1:])
|
||||
elif channel.startswith('+'):
|
||||
voices.append(channel[1:])
|
||||
else:
|
||||
normal.append(channel)
|
||||
L = []
|
||||
if ops:
|
||||
L.append(format(_('is an op on %L'), ops))
|
||||
if halfops:
|
||||
L.append(format(_('is a halfop on %L'), halfops))
|
||||
if voices:
|
||||
L.append(format(_('is voiced on %L'), voices))
|
||||
if normal:
|
||||
if L:
|
||||
L.append(format(_('is also on %L'), normal))
|
||||
else:
|
||||
L.append(format(_('is on %L'), normal))
|
||||
else:
|
||||
L = [_('isn\'t on any non-secret channels')]
|
||||
channels = format('%L', L)
|
||||
if '317' in d:
|
||||
idle = utils.timeElapsed(d['317'].args[2])
|
||||
signon = time.strftime(conf.supybot.reply.format.time(),
|
||||
time.localtime(float(d['317'].args[3])))
|
||||
else:
|
||||
idle = _('<unknown>')
|
||||
signon = _('<unknown>')
|
||||
if '312' in d:
|
||||
server = d['312'].args[2]
|
||||
else:
|
||||
server = _('<unknown>')
|
||||
if '301' in d:
|
||||
away = format(_(' %s is away: %s.'), nick, d['301'].args[2])
|
||||
else:
|
||||
away = ''
|
||||
if '320' in d:
|
||||
if d['320'].args[2]:
|
||||
identify = _(' identified')
|
||||
else:
|
||||
identify = ''
|
||||
else:
|
||||
identify = ''
|
||||
s = format(_('%s (%s) has been%s on server %s since %s (idle for %s) '
|
||||
'and %s.%s'),
|
||||
user, hostmask, identify, server, signon, idle,
|
||||
channels, away)
|
||||
d['318'] = msg
|
||||
s = ircutils.formatWhois(irc, d, caller=replyMsg.nick,
|
||||
channel=replyMsg.args[0])
|
||||
replyIrc.reply(s)
|
||||
del self._whois[(irc, loweredNick)]
|
||||
|
||||
|
@ -71,7 +71,7 @@ conf.registerChannelValue(ShrinkUrl, 'shrinkSnarfer',
|
||||
shrink snarfer is enabled. This snarfer will watch for URLs in the
|
||||
channel, and if they're sufficiently long (as determined by
|
||||
supybot.plugins.ShrinkUrl.minimumLength) it will post a
|
||||
smaller URL from tinyurl.com, as denoted in
|
||||
smaller URL from the service as denoted in
|
||||
supybot.plugins.ShrinkUrl.default.""")))
|
||||
conf.registerChannelValue(ShrinkUrl.shrinkSnarfer, 'showDomain',
|
||||
registry.Boolean(True, _("""Determines whether the snarfer will show the
|
||||
|
@ -1289,7 +1289,7 @@ class Commands(BasePlugin):
|
||||
if 'command has no help.' in help:
|
||||
# Note: this case will never happen, unless 'checkDoc' is set
|
||||
# to False.
|
||||
irc.error(_('Invalid arguments for %s.') % ' '.join(command))
|
||||
irc.error(_('Invalid arguments for %s.') % formatCommand(command))
|
||||
else:
|
||||
irc.reply(help)
|
||||
except (SyntaxError, Error) as e:
|
||||
|
@ -1,6 +1,6 @@
|
||||
###
|
||||
# Copyright (c) 2002-2005, Jeremiah Fincher
|
||||
# Copyright (c) 2009-2010, James McCoy
|
||||
# Copyright (c) 2009-2010,2015, James McCoy
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
@ -443,8 +443,8 @@ def _getRe(f):
|
||||
else:
|
||||
state.args.append(s)
|
||||
else:
|
||||
state.errorInvalid(_('regular expression'), s)
|
||||
except IndexError:
|
||||
raise ValueError
|
||||
except (ValueError, IndexError):
|
||||
args[:] = original
|
||||
state.errorInvalid(_('regular expression'), s)
|
||||
return get
|
||||
|
@ -1135,8 +1135,11 @@ class Irc(IrcCommandDispatcher):
|
||||
if not self.afterConnect:
|
||||
newNick = self._getNextNick()
|
||||
assert newNick != self.nick
|
||||
log.info('Got 433: %s %s. Trying %s.',self.nick, problem, newNick)
|
||||
log.info('Got %s: %s %s. Trying %s.',
|
||||
msg.command, self.nick, problem, newNick)
|
||||
self.sendMsg(ircmsgs.nick(newNick))
|
||||
def do437(self, msg):
|
||||
self.do43x(msg, 'is temporarily unavailable')
|
||||
def do433(self, msg):
|
||||
self.do43x(msg, 'is in use')
|
||||
def do432(self, msg):
|
||||
|
119
src/ircutils.py
119
src/ircutils.py
@ -1,6 +1,6 @@
|
||||
###
|
||||
# Copyright (c) 2002-2005, Jeremiah Fincher
|
||||
# Copyright (c) 2009,2011, James McCoy
|
||||
# Copyright (c) 2009,2011,2015 James McCoy
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
@ -375,6 +375,123 @@ def stripFormatting(s):
|
||||
s = stripUnderline(s)
|
||||
return s.replace('\x0f', '').replace('\x0F', '')
|
||||
|
||||
_containsFormattingRe = re.compile(r'[\x02\x03\x16\x1f]')
|
||||
def formatWhois(irc, replies, caller='', channel='', command='whois'):
|
||||
"""Returns a string describing the target of a WHOIS command.
|
||||
|
||||
Arguments are:
|
||||
* irc: the irclib.Irc object on which the replies was received
|
||||
|
||||
* replies: a dict mapping the reply codes ('311', '312', etc.) to their
|
||||
corresponding ircmsg.IrcMsg
|
||||
|
||||
* caller: an optional nick specifying who requested the whois information
|
||||
|
||||
* channel: an optional channel specifying where the reply will be sent
|
||||
|
||||
If provided, caller and channel will be used to avoid leaking information
|
||||
that the caller/channel shouldn't be privy to.
|
||||
"""
|
||||
hostmask = '@'.join(replies['311'].args[2:4])
|
||||
nick = replies['318'].args[1]
|
||||
user = replies['311'].args[-1]
|
||||
(replyIrc, replyMsg, d, command) = self._whois[(irc, loweredNick)]
|
||||
START_CODE = '311' if command == 'whois' else '314'
|
||||
hostmask = '@'.join(d[START_CODE].args[2:4])
|
||||
user = d[START_CODE].args[-1]
|
||||
if _containsFormattingRe.search(user) and user[-1] != '\x0f':
|
||||
# For good measure, disable any formatting
|
||||
user = '%s\x0f' % user
|
||||
if '319' in replies:
|
||||
channels = replies['319'].args[-1].split()
|
||||
ops = []
|
||||
voices = []
|
||||
normal = []
|
||||
halfops = []
|
||||
for chan in channels:
|
||||
origchan = chan
|
||||
chan = chan.lstrip('@%+~!')
|
||||
# UnrealIRCd uses & for user modes and disallows it as a
|
||||
# channel-prefix, flying in the face of the RFC. Have to
|
||||
# handle this specially when processing WHOIS response.
|
||||
testchan = chan.lstrip('&')
|
||||
if testchan != chan and irc.isChannel(testchan):
|
||||
chan = testchan
|
||||
diff = len(chan) - len(origchan)
|
||||
modes = origchan[:diff]
|
||||
chanState = irc.state.channels.get(chan)
|
||||
# The user is in a channel the bot is in, so the ircd may have
|
||||
# responded with otherwise private data.
|
||||
if chanState:
|
||||
# Skip channels the callee isn't in. This helps prevents
|
||||
# us leaking information when the channel is +s or the
|
||||
# target is +i
|
||||
if caller not in chanState.users:
|
||||
continue
|
||||
# Skip +s channels the target is in only if the reply isn't
|
||||
# being sent to that channel
|
||||
if 's' in chanState.modes and \
|
||||
not ircutils.strEqual(channel or '', chan):
|
||||
continue
|
||||
if not modes:
|
||||
normal.append(chan)
|
||||
elif utils.iter.any(lambda c: c in modes,('@', '&', '~', '!')):
|
||||
ops.append(chan[1:])
|
||||
elif utils.iter.any(lambda c: c in modes, ('%',)):
|
||||
halfops.append(chan[1:])
|
||||
elif utils.iter.any(lambda c: c in modes, ('+',)):
|
||||
voices.append(chan[1:])
|
||||
L = []
|
||||
if ops:
|
||||
L.append(format(_('is an op on %L'), ops))
|
||||
if halfops:
|
||||
L.append(format(_('is a halfop on %L'), halfops))
|
||||
if voices:
|
||||
L.append(format(_('is voiced on %L'), voices))
|
||||
if normal:
|
||||
if L:
|
||||
L.append(format(_('is also on %L'), normal))
|
||||
else:
|
||||
L.append(format(_('is on %L'), normal))
|
||||
else:
|
||||
if command == 'whois':
|
||||
L = [_('isn\'t on any non-secret channels')]
|
||||
else:
|
||||
L = []
|
||||
channels = format('%L', L)
|
||||
if '317' in replies:
|
||||
idle = utils.timeElapsed(replies['317'].args[2])
|
||||
signon = utils.str.timestamp(float(replies['317'].args[3]))
|
||||
else:
|
||||
idle = '<unknown>'
|
||||
signon = '<unknown>'
|
||||
if '312' in replies:
|
||||
server = replies['312'].args[2]
|
||||
if len(d['312']) > 3:
|
||||
signoff = d['312'].args[3]
|
||||
else:
|
||||
server = '<unknown>'
|
||||
if '301' in replies:
|
||||
away = ' %s is away: %s.' % (nick, replies['301'].args[2])
|
||||
else:
|
||||
away = ''
|
||||
if '320' in replies:
|
||||
if replies['320'].args[2]:
|
||||
identify = ' identified'
|
||||
else:
|
||||
identify = ''
|
||||
else:
|
||||
identify = ''
|
||||
if command == 'whois':
|
||||
s = _('%s (%s) has been%s on server %s since %s (idle for %s) and '
|
||||
'%s.%s').decode('utf8') % (user, hostmask, identify, server,
|
||||
signon, idle, channels, away)
|
||||
else:
|
||||
s = _('%s (%s) has been%s on server %s and disconnect on %s.') \
|
||||
.decode('utf8') % \
|
||||
(user, hostmask, identify, server, signoff)
|
||||
return s
|
||||
|
||||
class FormatContext(object):
|
||||
def __init__(self):
|
||||
self.reset()
|
||||
|
@ -1,5 +1,6 @@
|
||||
###
|
||||
# Copyright (c) 2002-2005, Jeremiah Fincher
|
||||
# Copyright (c) 2015, James McCoy
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
@ -196,13 +197,24 @@ class FirstTestCase(CommandsTestCase):
|
||||
self.assertStateErrored([first('int', 'something')], ['words'],
|
||||
errored=False)
|
||||
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
def testLongRegexp(self):
|
||||
spec = [first('regexpMatcher', 'regexpReplacer'), 'text']
|
||||
self.assertStateErrored(spec, ['s/foo/bar/', 'x' * 512], errored=False)
|
||||
|
||||
>>>>>>> supybot/master
|
||||
class GetoptTestCase(PluginTestCase):
|
||||
plugins = ('Misc',) # We put something so it does not complain
|
||||
class Foo(callbacks.Plugin):
|
||||
def bar(self, irc, msg, args, optlist):
|
||||
irc.reply(' '.join(sorted(['%s:%d'%x for x in optlist])))
|
||||
<<<<<<< HEAD
|
||||
bar = wrap(bar, [getopts({'foo': 'int', 'fbar': 'int'})],
|
||||
checkDoc=False)
|
||||
=======
|
||||
bar = wrap(bar, [getopts({'foo': 'int', 'fbar': 'int'})])
|
||||
>>>>>>> supybot/master
|
||||
|
||||
def testGetoptsExact(self):
|
||||
self.irc.addCallback(self.Foo(self.irc))
|
||||
@ -211,6 +223,9 @@ class GetoptTestCase(PluginTestCase):
|
||||
self.assertResponse('bar --f 3 --fb 5',
|
||||
'Error: Invalid arguments for bar.')
|
||||
|
||||
<<<<<<< HEAD
|
||||
|
||||
=======
|
||||
>>>>>>> supybot/master
|
||||
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user