Fix RFC-compliance of privmsgs/notices/kicks/whois/... with list of nicks/channels are argument. Closes GH-462.

This commit is contained in:
Valentin Lorentz 2013-03-23 11:06:08 +01:00
parent 5209cbc402
commit 574d73c14e
3 changed files with 44 additions and 7 deletions

View File

@ -337,7 +337,10 @@ def prettyPrint(msg, addRecipients=False, timestampFormat=None, showNick=True):
### ###
isNick = ircutils.isNick isNick = ircutils.isNick
areNicks = ircutils.areNicks
isChannel = ircutils.isChannel isChannel = ircutils.isChannel
areChannels = ircutils.areChannels
areReceivers = ircutils.areReceivers
isUserHostmask = ircutils.isUserHostmask isUserHostmask = ircutils.isUserHostmask
def pong(payload, prefix='', msg=None): def pong(payload, prefix='', msg=None):
@ -545,12 +548,14 @@ def kick(channel, nick, s='', prefix='', msg=None):
return IrcMsg(prefix=prefix, command='KICK', return IrcMsg(prefix=prefix, command='KICK',
args=(channel, nick), msg=msg) args=(channel, nick), msg=msg)
def kicks(channel, nicks, s='', prefix='', msg=None): def kicks(channels, nicks, s='', prefix='', msg=None):
"""Returns a KICK to kick each of nicks from channel with the message msg. """Returns a KICK to kick each of nicks from channel with the message msg.
""" """
if isinstance(channels, str): # Backward compatibility
channels = [channels]
if conf.supybot.protocols.irc.strictRfc(): if conf.supybot.protocols.irc.strictRfc():
assert isChannel(channel), repr(channel) assert areChannels(channels), repr(channel)
assert all(isNick, nicks), nicks assert areNicks(nicks), repr(nicks)
if msg and not prefix: if msg and not prefix:
prefix = msg.prefix prefix = msg.prefix
if sys.version_info[0] < 3 and isinstance(s, unicode): if sys.version_info[0] < 3 and isinstance(s, unicode):
@ -566,7 +571,7 @@ def kicks(channel, nicks, s='', prefix='', msg=None):
def privmsg(recipient, s, prefix='', msg=None): def privmsg(recipient, s, prefix='', msg=None):
"""Returns a PRIVMSG to recipient with the message msg.""" """Returns a PRIVMSG to recipient with the message msg."""
if conf.supybot.protocols.irc.strictRfc(): if conf.supybot.protocols.irc.strictRfc():
assert (isChannel(recipient) or isNick(recipient)), repr(recipient) assert (areReceivers(recipient)), repr(recipient)
assert s, 's must not be empty.' assert s, 's must not be empty.'
if sys.version_info[0] < 3 and isinstance(s, unicode): if sys.version_info[0] < 3 and isinstance(s, unicode):
s = s.encode('utf8') s = s.encode('utf8')
@ -598,7 +603,7 @@ def action(recipient, s, prefix='', msg=None):
def notice(recipient, s, prefix='', msg=None): def notice(recipient, s, prefix='', msg=None):
"""Returns a NOTICE to recipient with the message msg.""" """Returns a NOTICE to recipient with the message msg."""
if conf.supybot.protocols.irc.strictRfc(): if conf.supybot.protocols.irc.strictRfc():
assert (isChannel(recipient) or isNick(recipient)), repr(recipient) assert areReceivers(recipient), repr(recipient)
assert s, 'msg must not be empty.' assert s, 'msg must not be empty.'
if sys.version_info[0] < 3 and isinstance(s, unicode): if sys.version_info[0] < 3 and isinstance(s, unicode):
s = s.encode('utf8') s = s.encode('utf8')
@ -735,7 +740,7 @@ def who(hostmaskOrChannel, prefix='', msg=None):
def whois(nick, mask='', prefix='', msg=None): def whois(nick, mask='', prefix='', msg=None):
"""Returns a WHOIS for nick.""" """Returns a WHOIS for nick."""
if conf.supybot.protocols.irc.strictRfc(): if conf.supybot.protocols.irc.strictRfc():
assert isNick(nick), repr(nick) assert areNicks(nick), repr(nick)
if msg and not prefix: if msg and not prefix:
prefix = msg.prefix prefix = msg.prefix
args = (nick,) args = (nick,)
@ -745,7 +750,7 @@ def whois(nick, mask='', prefix='', msg=None):
def names(channel=None, prefix='', msg=None): def names(channel=None, prefix='', msg=None):
if conf.supybot.protocols.irc.strictRfc(): if conf.supybot.protocols.irc.strictRfc():
assert isChannel(channel) assert areChannels(channel)
if msg and not prefix: if msg and not prefix:
prefix = msg.prefix prefix = msg.prefix
if channel is not None: if channel is not None:

View File

@ -43,6 +43,7 @@ import time
import random import random
import string import string
import textwrap import textwrap
import functools
from cStringIO import StringIO as sio from cStringIO import StringIO as sio
import supybot.utils as utils import supybot.utils as utils
@ -132,6 +133,11 @@ def isNick(s, strictRfc=True, nicklen=None):
not isUserHostmask(s) and \ not isUserHostmask(s) and \
not ' ' in s and not '!' in s not ' ' in s and not '!' in s
def areNicks(s, strictRfc=True, nicklen=None):
"""Like 'isNick(x)' but for comma-separated list."""
nick = functools.partial(isNick, strictRfc=strictRfc, nicklen=nicklen)
return all(map(nick, s.split(',')))
def isChannel(s, chantypes='#&+!', channellen=50): def isChannel(s, chantypes='#&+!', channellen=50):
"""s => bool """s => bool
Returns True if s is a valid IRC channel name.""" Returns True if s is a valid IRC channel name."""
@ -142,6 +148,20 @@ def isChannel(s, chantypes='#&+!', channellen=50):
len(s) <= channellen and \ len(s) <= channellen and \
len(s.split(None, 1)) == 1 len(s.split(None, 1)) == 1
def areChannels(s, chantypes='#&+!',channellen=50):
"""Like 'isChannel(x)' but for comma-separated list."""
chan = functools.partial(isChannel, chantypes=chantypes,
channellen=channellen)
return all(map(chan, s.split(',')))
def areReceivers(s, strictRfc=True, nicklen=None, chantypes='#&+!',
channellen=50):
"""Like 'isNick(x) or isChannel(x)' but for comma-separated list."""
nick = functools.partial(isNick, strictRfc=strictRfc, nicklen=nicklen)
chan = functools.partial(isChannel, chantypes=chantypes,
channellen=channellen)
return all(map(lambda x:nick(x) or chan(x), s.split(',')))
_patternCache = utils.structures.CacheDict(1000) _patternCache = utils.structures.CacheDict(1000)
def _hostmaskPatternEqual(pattern, hostmask): def _hostmaskPatternEqual(pattern, hostmask):
try: try:

View File

@ -161,6 +161,18 @@ class FunctionsTestCase(SupyTestCase):
msg = ircmsgs.action('#foo', s) msg = ircmsgs.action('#foo', s)
self.assertEqual(ircmsgs.unAction(msg), s) self.assertEqual(ircmsgs.unAction(msg), s)
def testPrivmsg(self):
self.assertEqual(str(ircmsgs.privmsg('foo', 'bar')),
'PRIVMSG foo :bar\r\n')
self.assertEqual(str(ircmsgs.privmsg('foo,bar', 'baz')),
'PRIVMSG foo,bar :baz\r\n')
def testWhois(self):
self.assertEqual(str(ircmsgs.whois('foo')), 'WHOIS :foo\r\n')
self.assertEqual(str(ircmsgs.whois('foo,bar')), 'WHOIS :foo,bar\r\n')
self.assertRaises(AssertionError, ircmsgs.whois, '#foo')
self.assertRaises(AssertionError, ircmsgs.whois, 'foo,#foo')
def testBan(self): def testBan(self):
channel = '#osu' channel = '#osu'
ban = '*!*@*.edu' ban = '*!*@*.edu'