From cb48912db6d3dec473d73f1cfa3754547034896f Mon Sep 17 00:00:00 2001 From: James Vega Date: Sun, 3 Oct 2010 14:58:38 -0400 Subject: [PATCH 01/15] Services: Correct formatting of "isn't registered" log. Closes: Sf#3075937 Signed-off-by: James Vega --- plugins/Services/plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/Services/plugin.py b/plugins/Services/plugin.py index e5882573b..1d17a8085 100644 --- a/plugins/Services/plugin.py +++ b/plugins/Services/plugin.py @@ -244,7 +244,7 @@ class Services(callbacks.Plugin): # You have been unbanned from (oftc) irc.sendMsg(networkGroup.channels.join(channel)) elif 'isn\'t registered' in s: - self.log.warning('Received "%s isn\'t registered" from ChanServ %', + self.log.warning('Received "%s isn\'t registered" from ChanServ %s', channel, on) elif 'this channel has been registered' in s: self.log.debug('Got "Registered channel" from ChanServ %s.', on) From 543e78828b258fe764017e95ebdd30d39fd74555 Mon Sep 17 00:00:00 2001 From: James Vega Date: Mon, 6 Jun 2011 21:44:15 -0400 Subject: [PATCH 02/15] Add utils.net.isIPV4, with utils.net.isIP checking v4 or v6 Signed-off-by: James Vega --- src/conf.py | 4 ++-- src/ircutils.py | 7 ++++--- src/utils/net.py | 20 ++++++++++++++++---- test/test_utils.py | 6 ++---- 4 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/conf.py b/src/conf.py index b00b495c4..efc87aadd 100644 --- a/src/conf.py +++ b/src/conf.py @@ -1,6 +1,6 @@ ### # Copyright (c) 2002-2005, Jeremiah Fincher -# Copyright (c) 2008-2009, James Vega +# Copyright (c) 2008-2009,2011, James Vega # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -1031,7 +1031,7 @@ registerGlobalValue(supybot, 'defaultIgnore', class IP(registry.String): """Value must be a valid IP.""" def setValue(self, v): - if v and not (utils.net.isIP(v) or utils.net.isIPV6(v)): + if v and not utils.net.isIP(v): self.error() else: registry.String.setValue(self, v) diff --git a/src/ircutils.py b/src/ircutils.py index 815259060..7cfa70568 100644 --- a/src/ircutils.py +++ b/src/ircutils.py @@ -1,5 +1,6 @@ ### # Copyright (c) 2002-2005, Jeremiah Fincher +# Copyright (c) 2011, James Vega # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -190,7 +191,7 @@ def banmask(hostmask): """ assert isUserHostmask(hostmask) host = hostFromHostmask(hostmask) - if utils.net.isIP(host): + if utils.net.isIPV4(host): L = host.split('.') L[-1] = '*' return '*!*@' + '.'.join(L) @@ -461,8 +462,8 @@ def replyTo(msg): return msg.nick def dccIP(ip): - """Returns in IP in the proper for DCC.""" - assert utils.net.isIP(ip), \ + """Returns an IP in the proper for DCC.""" + assert utils.net.isIPV4(ip), \ 'argument must be a string ip in xxx.yyy.zzz.www format.' i = 0 x = 256**3 diff --git a/src/utils/net.py b/src/utils/net.py index fa78fdcc3..ffe8c2005 100644 --- a/src/utils/net.py +++ b/src/utils/net.py @@ -1,5 +1,6 @@ ### # Copyright (c) 2002-2005, Jeremiah Fincher +# Copyright (c) 2011, James Vega # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -44,7 +45,7 @@ def getSocket(host): """ addrinfo = socket.getaddrinfo(host, None) host = addrinfo[0][4][0] - if isIP(host): + if isIPV4(host): return socket.socket(socket.AF_INET, socket.SOCK_STREAM) elif isIPV6(host): return socket.socket(socket.AF_INET6, socket.SOCK_STREAM) @@ -52,16 +53,27 @@ def getSocket(host): raise socket.error, 'Something wonky happened.' def isIP(s): - """Returns whether or not a given string is an IPV4 address. + """Returns whether or not a given string is an IP address. >>> isIP('255.255.255.255') 1 - >>> isIP('abc.abc.abc.abc') + >>> isIP('::1') + 0 + """ + return isIPV4(s) or isIPV6(s) + +def isIPV4(s): + """Returns whether or not a given string is an IPV4 address. + + >>> isIPV4('255.255.255.255') + 1 + + >>> isIPV4('abc.abc.abc.abc') 0 """ try: - return bool(socket.inet_aton(s)) + return bool(socket.inet_pton(socket.AF_INET, s)) except socket.error: return False diff --git a/test/test_utils.py b/test/test_utils.py index c61132181..82d8efb3f 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -1,6 +1,6 @@ ### # Copyright (c) 2002-2005, Jeremiah Fincher -# Copyright (c) 2009, James Vega +# Copyright (c) 2009,2011, James Vega # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -510,11 +510,9 @@ class NetTest(SupyTestCase): isIP = utils.net.isIP self.failIf(isIP('a.b.c')) self.failIf(isIP('256.0.0.0')) - self.failUnless(isIP('127.1')) self.failUnless(isIP('0.0.0.0')) self.failUnless(isIP('100.100.100.100')) - # This test is too flaky to bother with. - # self.failUnless(utils.isIP('255.255.255.255')) + self.failUnless(isIP('255.255.255.255')) def testIsIPV6(self): f = utils.net.isIPV6 From d56381436c3dc9e574384a3c935ecf18fbb024f7 Mon Sep 17 00:00:00 2001 From: James Vega Date: Mon, 6 Jun 2011 22:28:35 -0400 Subject: [PATCH 03/15] Update Internet.dns to handle IPv6 IPs and responses Signed-off-by: James Vega --- plugins/Internet/plugin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/Internet/plugin.py b/plugins/Internet/plugin.py index 490c9165c..eb5354394 100644 --- a/plugins/Internet/plugin.py +++ b/plugins/Internet/plugin.py @@ -1,6 +1,6 @@ ### # Copyright (c) 2003-2005, Jeremiah Fincher -# Copyright (c) 2010, James Vega +# Copyright (c) 2010-2011, James Vega # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -53,7 +53,7 @@ class Internet(callbacks.Plugin): irc.reply(hostname) else: try: - ip = socket.gethostbyname(host) + ip = socket.getaddrinfo(host, None)[0][4][0] if ip == '64.94.110.11': # Verisign sucks! irc.reply('Host not found.') else: From b0e595fbd2e9b244738f4f8b1b5b88831583ad03 Mon Sep 17 00:00:00 2001 From: James Vega Date: Mon, 6 Jun 2011 22:29:21 -0400 Subject: [PATCH 04/15] Update Internet.hexip to handle IPv6 Signed-off-by: James Vega --- plugins/Internet/plugin.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/plugins/Internet/plugin.py b/plugins/Internet/plugin.py index eb5354394..de94afcd9 100644 --- a/plugins/Internet/plugin.py +++ b/plugins/Internet/plugin.py @@ -149,12 +149,22 @@ class Internet(callbacks.Plugin): Returns the hexadecimal IP for that IP. """ - quads = ip.split('.') ret = "" - for quad in quads: - i = int(quad) - ret += '%02x' % i - irc.reply(ret.upper()) + if utils.net.isIPV4(ip): + quads = ip.split('.') + for quad in quads: + i = int(quad) + ret += '%02X' % i + else: + octets = ip.split(':') + for octet in octets: + if octet: + i = int(octet, 16) + ret += '%04X' % i + else: + missing = (8 - len(octets)) * 4 + ret += '0' * missing + irc.reply(ret) hexip = wrap(hexip, ['ip']) From 0cd4939678e5839c85b57460c7c4b000c8fc1751 Mon Sep 17 00:00:00 2001 From: James Vega Date: Tue, 2 Aug 2011 22:19:47 -0400 Subject: [PATCH 05/15] Seen: Anchor nick regexp to ensure valid match. When searching for 'st*ke', 'stryker' would incorrectly match, 'stryke' would be added to the nick set and the subsequent lookup would cause a KeyError. This is fixed both by anchoring the regexp ('^st.*ke$' instead of 'st.*ke') and adding searchNick to the nick set instead of the string that matched the pattern. Closes: Sf#3377381 Signed-off-by: James Vega --- plugins/Seen/plugin.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/plugins/Seen/plugin.py b/plugins/Seen/plugin.py index d5bc6275e..c4255b172 100644 --- a/plugins/Seen/plugin.py +++ b/plugins/Seen/plugin.py @@ -1,6 +1,6 @@ ### # Copyright (c) 2002-2004, Jeremiah Fincher -# Copyright (c) 2010, James Vega +# Copyright (c) 2010-2011, James Vega # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -66,7 +66,7 @@ class SeenDB(plugins.ChannelUserDB): def seenWildcard(self, channel, nick): nicks = ircutils.IrcSet() - nickRe = re.compile('.*'.join(nick.split('*')), re.I) + nickRe = re.compile('^%s$' % '.*'.join(nick.split('*')), re.I) for (searchChan, searchNick) in self.keys(): #print 'chan: %s ... nick: %s' % (searchChan, searchNick) if isinstance(searchNick, int): @@ -75,11 +75,8 @@ class SeenDB(plugins.ChannelUserDB): # are keyed by nick-string continue if ircutils.strEqual(searchChan, channel): - try: - s = nickRe.match(searchNick).group() - except AttributeError: - continue - nicks.add(s) + if nickRe.search(searchNick) is not None: + nicks.add(searchNick) L = [[nick, self.seen(channel, nick)] for nick in nicks] def negativeTime(x): return -x[1][0] From 4661acb3a3e1f6bd5773ead9aa290995cfc2bfa4 Mon Sep 17 00:00:00 2001 From: James Vega Date: Mon, 22 Aug 2011 14:07:39 -0400 Subject: [PATCH 06/15] Honor supybot-test's timeout option and document the units Signed-off-by: James Vega --- scripts/supybot-test | 6 ++++-- src/test.py | 5 ++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/scripts/supybot-test b/scripts/supybot-test index 2bec1826e..c0a500713 100644 --- a/scripts/supybot-test +++ b/scripts/supybot-test @@ -2,6 +2,7 @@ ### # Copyright (c) 2002-2005, Jeremiah Fincher +# Copyright (c) 2011, James Vega # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -122,9 +123,10 @@ if __name__ == '__main__': parser.add_option('-c', '--clean', action='store_true', default=False, dest='clean', help='Cleans the various data/conf/logs' 'directories before running tests.') - parser.add_option('-t', '--timeout', action='store', type='int', + parser.add_option('-t', '--timeout', action='store', type='float', dest='timeout', - help='Sets the timeout for tests to return responses.') + help='Sets the timeout, in seconds, for tests to return ' + 'responses.') parser.add_option('-v', '--verbose', action='store_true', default=False, help='Sets the verbose flag, logging extra information ' 'about each test that runs.') diff --git a/src/test.py b/src/test.py index f0e2826df..7a3280bbe 100644 --- a/src/test.py +++ b/src/test.py @@ -1,5 +1,6 @@ ### # Copyright (c) 2002-2005, Jeremiah Fincher +# Copyright (c) 2011, James Vega # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -54,6 +55,8 @@ network = True # This is the global list of suites that are to be run. suites = [] +timeout = 10 + originalCallbacksGetHelp = callbacks.getHelp lastGetHelp = 'x'*1000 def cachingGetHelp(method, name=None, doc=None): @@ -110,12 +113,12 @@ class PluginTestCase(SupyTestCase): """Subclass this to write a test case for a plugin. See plugins/Plugin/test.py for an example. """ - timeout = 10 plugins = None cleanConfDir = True cleanDataDir = True config = {} def __init__(self, methodName='runTest'): + self.timeout = timeout originalRunTest = getattr(self, methodName) def runTest(self): run = True From df5391dcf72e0113daecbb78e88cc2ac15ed8e89 Mon Sep 17 00:00:00 2001 From: Daniel Folkinshteyn Date: Sun, 11 Jul 2010 02:29:02 -0400 Subject: [PATCH 07/15] Socket driver: implement ssl connection support. Signed-off-by: James McCoy --- src/drivers/Socket.py | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/drivers/Socket.py b/src/drivers/Socket.py index 6db605a59..ff9e59146 100644 --- a/src/drivers/Socket.py +++ b/src/drivers/Socket.py @@ -46,6 +46,13 @@ import supybot.drivers as drivers import supybot.schedule as schedule from supybot.utils.iter import imap +try: + import ssl +except ImportError: + drivers.log.debug('ssl module is not available, ' + 'cannot connect to SSL servers.') + ssl = None + class SocketDriver(drivers.IrcDriver, drivers.ServersMixin): def __init__(self, irc): self.irc = irc @@ -61,12 +68,7 @@ class SocketDriver(drivers.IrcDriver, drivers.ServersMixin): self.writeCheckTime = None self.nextReconnectTime = None self.resetDelay() - # Only connect to non-SSL servers - if self.networkGroup.get('ssl').value: - drivers.log.error('The Socket driver can not connect to SSL ' - 'servers. Try the Twisted driver instead.') - else: - self.connect() + self.connect() def getDelay(self): ret = self.currentDelay @@ -139,6 +141,12 @@ class SocketDriver(drivers.IrcDriver, drivers.ServersMixin): self.irc.feedMsg(msg) except socket.timeout: pass + except ssl.SSLError, e: + if e.args[0] == 'The read operation timed out': + pass + else: + self._handleSocketError(e) + return except socket.error, e: self._handleSocketError(e) return @@ -163,6 +171,14 @@ class SocketDriver(drivers.IrcDriver, drivers.ServersMixin): drivers.log.connect(self.currentServer) try: self.conn = utils.net.getSocket(server[0]) + if self.networkGroup.get('ssl').value: + if ssl: + self.plainconn = self.conn + self.conn = ssl.wrap_socket(self.conn) + else: + drivers.log.error('ssl module not available, ' + 'cannot connect to SSL servers.') + return vhost = conf.supybot.protocols.irc.vhost() self.conn.bind((vhost, 0)) except socket.error, e: From 8f7c4bdf7f1e0d779d7b382440d62603df49582e Mon Sep 17 00:00:00 2001 From: Daniel Folkinshteyn Date: Mon, 24 Jan 2011 16:09:18 -0500 Subject: [PATCH 08/15] Fix banmask creation. Thanks Progval for the patch! fixes https://sourceforge.net/tracker/?func=detail&aid=3088559&group_id=58965&atid=489447 incorporating patch https://sourceforge.net/tracker/?func=detail&aid=3163843&group_id=58965&atid=489449 Signed-off-by: James McCoy --- src/ircutils.py | 2 +- test/test_ircutils.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ircutils.py b/src/ircutils.py index 7cfa70568..2b03797b9 100644 --- a/src/ircutils.py +++ b/src/ircutils.py @@ -200,7 +200,7 @@ def banmask(hostmask): L[-1] = '*' return '*!*@' + ':'.join(L) else: - if '.' in host: + if len(host.split('.')) > 2: # If it is a subdomain return '*!*@*%s' % host[host.find('.'):] else: return '*!*@' + host diff --git a/test/test_ircutils.py b/test/test_ircutils.py index a6b73b154..1df39660b 100644 --- a/test/test_ircutils.py +++ b/test/test_ircutils.py @@ -214,6 +214,10 @@ class FunctionsTestCase(SupyTestCase): msg.prefix), '%r didn\'t match %r' % (msg.prefix, banmask)) self.assertEqual(ircutils.banmask('foobar!user@host'), '*!*@host') + self.assertEqual(ircutils.banmask('foobar!user@host.tld'), + '*!*@host.tld') + self.assertEqual(ircutils.banmask('foobar!user@sub.host.tld'), + '*!*@*.host.tld') self.assertEqual(ircutils.banmask('foo!bar@2001::'), '*!*@2001::*') def testSeparateModes(self): From 01c8dc7f78352c6e11b75b67efa0f816e0881702 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Sat, 22 Oct 2011 14:57:20 -0400 Subject: [PATCH 09/15] String.decode: Only encode('utf-8') when the decode string is unicode Closes: Sf#3165718 Signed-off-by: James McCoy --- plugins/String/plugin.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/String/plugin.py b/plugins/String/plugin.py index cbacafd3f..bcfc1caa4 100644 --- a/plugins/String/plugin.py +++ b/plugins/String/plugin.py @@ -79,7 +79,12 @@ class String(callbacks.Plugin): . """ try: - irc.reply(text.decode(encoding).encode('utf-8')) + s = text.decode(encoding) + # Not all encodings decode to a unicode object. Only encode those + # that do. + if isinstance(s, unicode): + s = s.encode('utf-8') + irc.reply(s) except LookupError: irc.errorInvalid('encoding', encoding) except binascii.Error: From 964c73f591f7eafed94d7bcd6dd7b94dbb0afad5 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Sat, 22 Oct 2011 15:23:56 -0400 Subject: [PATCH 10/15] RSS._getConverter: Encode strings before handing them off to other functions When the feed has a specified encoding, we'll be dealing with unicode objects in the response from feedparser.parse(). To avoid possible UnicodeErrors, we need to encode() before handing the string off to other functions, so the other functions are always dealing with bytestrings instead of bytestrings and unicode objects. Mixing unicode and bytestrings will cause implicit conversions of the unicode objects, which will most likely use the wrong encoding. Signed-off-by: James McCoy --- plugins/RSS/plugin.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/plugins/RSS/plugin.py b/plugins/RSS/plugin.py index b2fb31b7b..bf871b11f 100644 --- a/plugins/RSS/plugin.py +++ b/plugins/RSS/plugin.py @@ -262,8 +262,14 @@ class RSS(callbacks.Plugin): def _getConverter(self, feed): toText = utils.web.htmlToText if 'encoding' in feed: - return lambda s: toText(s).strip().encode(feed['encoding'], - 'replace') + def conv(s): + # encode() first so there implicit encoding doesn't happen in + # other functions when unicode and bytestring objects are used + # together + s = s.encode(feed['encoding'], 'replace') + s = toText(s).strip() + return s + return conv else: return lambda s: toText(s).strip() From c91916ae5eb6ccd5dcd098a16200d9571122889d Mon Sep 17 00:00:00 2001 From: James McCoy Date: Sat, 29 Oct 2011 17:53:35 -0400 Subject: [PATCH 11/15] Misc: Avoid setting up "invalid command" flood handling if its not enabled Closes: Sf#3088554 Signed-off-by: James McCoy --- plugins/Misc/plugin.py | 49 ++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/plugins/Misc/plugin.py b/plugins/Misc/plugin.py index 91f944f2e..702a70b3b 100644 --- a/plugins/Misc/plugin.py +++ b/plugins/Misc/plugin.py @@ -58,30 +58,33 @@ class Misc(callbacks.Plugin): assert not msg.repliedTo, 'repliedTo msg in Misc.invalidCommand.' assert self is irc.callbacks[-1], 'Misc isn\'t last callback.' self.log.debug('Misc.invalidCommand called (tokens %s)', tokens) - # First, we check for invalidCommand floods. This is rightfully done - # here since this will be the last invalidCommand called, and thus it - # will only be called if this is *truly* an invalid command. - maximum = conf.supybot.abuse.flood.command.invalid.maximum() - self.invalidCommands.enqueue(msg) - if self.invalidCommands.len(msg) > maximum and \ - conf.supybot.abuse.flood.command.invalid() and \ - not ircdb.checkCapability(msg.prefix, 'owner'): - punishment = conf.supybot.abuse.flood.command.invalid.punishment() - banmask = '*!%s@%s' % (msg.user, msg.host) - self.log.info('Ignoring %s for %s seconds due to an apparent ' - 'invalid command flood.', banmask, punishment) - if tokens and tokens[0] == 'Error:': - self.log.warning('Apparent error loop with another Supybot ' - 'observed. Consider ignoring this bot ' - 'permanently.') - ircdb.ignores.add(banmask, time.time() + punishment) - irc.reply('You\'ve given me %s invalid commands within the last ' - 'minute; I\'m now ignoring you for %s.' % - (maximum, - utils.timeElapsed(punishment, seconds=False))) - return - # Now, for normal handling. channel = msg.args[0] + # Only bother with the invaildCommand flood handling if it's actually + # enabled + if conf.supybot.abuse.flood.command.invalid(): + # First, we check for invalidCommand floods. This is rightfully done + # here since this will be the last invalidCommand called, and thus it + # will only be called if this is *truly* an invalid command. + maximum = conf.supybot.abuse.flood.command.invalid.maximum() + banmasker = conf.supybot.protocols.irc.banmask.makeBanmask + self.invalidCommands.enqueue(msg) + if self.invalidCommands.len(msg) > maximum and \ + not ircdb.checkCapability(msg.prefix, 'owner'): + penalty = conf.supybot.abuse.flood.command.invalid.punishment() + banmask = banmasker(msg.prefix) + self.log.info('Ignoring %s for %s seconds due to an apparent ' + 'invalid command flood.', banmask, penalty) + if tokens and tokens[0] == 'Error:': + self.log.warning('Apparent error loop with another Supybot ' + 'observed. Consider ignoring this bot ' + 'permanently.') + ircdb.ignores.add(banmask, time.time() + penalty) + irc.reply('You\'ve given me %s invalid commands within the last ' + 'minute; I\'m now ignoring you for %s.' % + (maximum, + utils.timeElapsed(penalty, seconds=False))) + return + # Now, for normal handling. if conf.get(conf.supybot.reply.whenNotCommand, channel): if len(tokens) >= 2: cb = irc.getCallback(tokens[0]) From 3bfda3cc7ac52ff0fd13150f044f9b5b9c4f03e2 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Sun, 6 Nov 2011 22:20:55 -0500 Subject: [PATCH 12/15] Fix filtering of unsupported umodes Signed-off-by: James McCoy --- src/irclib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/irclib.py b/src/irclib.py index aa313f6ea..c095a4fe3 100644 --- a/src/irclib.py +++ b/src/irclib.py @@ -934,7 +934,7 @@ class Irc(IrcCommandDispatcher): if umodes[0] in '+-': (addSub, umodes) = (umodes[0], umodes[1:]) if supported: - umodes = filter(lamda m: m in supported, umodes) + umodes = [m for m in umodes if m in supported] umodes = ''.join(addSub, umodes) log.info('Sending user modes to %s: %s', self.network, umodes) self.sendMsg(ircmsgs.mode(self.nick, umodes)) From 4232e40e262cbbdb675b1cf315c43f576d8b1f43 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Mon, 7 Nov 2011 05:58:27 -0500 Subject: [PATCH 13/15] Fix parsing of 004 message for supported umodes/chanmodes Signed-off-by: James McCoy --- src/irclib.py | 6 +++--- test/test_irclib.py | 7 +++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/irclib.py b/src/irclib.py index c095a4fe3..e33863e52 100644 --- a/src/irclib.py +++ b/src/irclib.py @@ -404,10 +404,10 @@ class IrcState(IrcCommandDispatcher): """Handles parsing the 004 reply Supported user and channel modes are cached""" - # msg.args = [nick, server, ircd-version, umodes, modes, + # msg.args = [server, ircd-version, umodes, modes, # modes that require arguments? (non-standard)] - self.supported['umodes'] = msg.args[3] - self.supported['chanmodes'] = msg.args[4] + self.supported['umodes'] = msg.args[2] + self.supported['chanmodes'] = msg.args[3] _005converters = utils.InsensitivePreservingDict({ 'modes': int, diff --git a/test/test_irclib.py b/test/test_irclib.py index 52dc7e258..bda696be6 100644 --- a/test/test_irclib.py +++ b/test/test_irclib.py @@ -290,6 +290,13 @@ class IrcStateTestCase(SupyTestCase): state.addMsg(self.irc, ircmsgs.IrcMsg(':irc.inet.tele.dk 005 adkwbot WALLCHOPS KNOCK EXCEPTS INVEX MODES=4 MAXCHANNELS=20 MAXBANS=beI:100 MAXTARGETS=4 NICKLEN=9 TOPICLEN=120 KICKLEN=90 :are supported by this server')) self.assertEqual(state.supported['maxbans'], 100) + def testSupportedUmodes(self): + state = irclib.IrcState() + state.addMsg(self.irc, ircmsgs.IrcMsg(':charm.oftc.net 004 charm.oftc.net hybrid-7.2.2+oftc1.6.8 CDGPRSabcdfgiklnorsuwxyz biklmnopstveI bkloveI')) + self.assertEqual(state.supported['umodes'], 'CDGPRSabcdfgiklnorsuwxyz') + self.assertEqual(state.supported['chanmodes'], + 'biklmnopstveI') + def testEmptyTopic(self): state = irclib.IrcState() state.addMsg(self.irc, ircmsgs.topic('#foo')) From d6336421e0940120005b73676baf20560f4f8c78 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Mon, 7 Nov 2011 05:58:48 -0500 Subject: [PATCH 14/15] Fix IRC.do376's handling of supported state Signed-off-by: James McCoy --- src/irclib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/irclib.py b/src/irclib.py index e33863e52..cbc9f8882 100644 --- a/src/irclib.py +++ b/src/irclib.py @@ -928,13 +928,13 @@ class Irc(IrcCommandDispatcher): # Let's reset nicks in case we had to use a weird one. self.alternateNicks = conf.supybot.nick.alternates()[:] umodes = conf.supybot.protocols.irc.umodes() - supported = self.supported.get('umodes') + supported = self.state.supported.get('umodes') if umodes: addSub = '+' if umodes[0] in '+-': (addSub, umodes) = (umodes[0], umodes[1:]) if supported: - umodes = [m for m in umodes if m in supported] + umodes = ''.join([m for m in umodes if m in supported]) umodes = ''.join(addSub, umodes) log.info('Sending user modes to %s: %s', self.network, umodes) self.sendMsg(ircmsgs.mode(self.nick, umodes)) From 4833976294805763f7f7ebfd6adaa04864c2b500 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Sun, 13 Nov 2011 15:10:16 -0500 Subject: [PATCH 15/15] One last fix to umode filtering. Signed-off-by: James McCoy --- src/irclib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/irclib.py b/src/irclib.py index cbc9f8882..4f7fc7951 100644 --- a/src/irclib.py +++ b/src/irclib.py @@ -935,7 +935,7 @@ class Irc(IrcCommandDispatcher): (addSub, umodes) = (umodes[0], umodes[1:]) if supported: umodes = ''.join([m for m in umodes if m in supported]) - umodes = ''.join(addSub, umodes) + umodes = ''.join([addSub, umodes]) log.info('Sending user modes to %s: %s', self.network, umodes) self.sendMsg(ircmsgs.mode(self.nick, umodes)) do377 = do422 = do376