From 9168880204a3dffc8ff9cb3f092b3d5f59dd34ea Mon Sep 17 00:00:00 2001 From: James Lu Date: Mon, 26 Aug 2019 15:43:16 -0700 Subject: [PATCH] parse_modes: fix handling of +b-b ban cycles --- classes.py | 13 ++++++++++--- test/protocol_test_fixture.py | 23 +++++++++++++++++++++++ 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/classes.py b/classes.py index eddbdeb..d514da9 100644 --- a/classes.py +++ b/classes.py @@ -952,13 +952,13 @@ class PyLinkNetworkCoreWithUtils(PyLinkNetworkCore): arg = oldarg log.debug("Mode %s: coersing argument of '*' to %r.", mode, arg) - log.debug('(%s) parse_modes: checking if +%s %s is in old modes list: %s', self.name, mode, arg, existing) + log.debug('(%s) parse_modes: checking if +%s %s is in old modes list: %s; existing_casemap=%s', self.name, mode, arg, existing, existing_casemap) arg = self.to_lower(arg) casefolded_modepair = existing_casemap.get((mode, arg)) # Case fold arguments as needed if casefolded_modepair not in existing: # Ignore attempts to unset parameter modes that don't exist. - log.debug("(%s) parse_modes(): ignoring removal of non-existent list mode +%s %s", self.name, mode, arg) + log.debug("(%s) parse_modes: ignoring removal of non-existent list mode +%s %s; casefolded_modepair=%s", self.name, mode, arg, casefolded_modepair) continue arg = casefolded_modepair[1] @@ -975,9 +975,16 @@ class PyLinkNetworkCoreWithUtils(PyLinkNetworkCore): newmode = (prefix + mode, arg) res.append(newmode) - # Tentatively apply the new mode to the "existing" mode list. + # Tentatively apply the new mode to the "existing" mode list. This is so queries + # like +b-b *!*@example.com *!*@example.com behave correctly + # (we can't rely on the original mode list to check whether a mode currently exists) existing = self._apply_modes(existing, [newmode], is_channel=is_channel) + lowered_mode = (newmode[0][-1], self.to_lower(newmode[1]) if newmode[1] else newmode[1]) + if prefix == '+' and lowered_mode not in existing_casemap: + existing_casemap[lowered_mode] = (mode, arg) + elif prefix == '-' and lowered_mode in existing_casemap: + del existing_casemap[lowered_mode] return res def parse_modes(self, target, args, ignore_missing_args=False): diff --git a/test/protocol_test_fixture.py b/test/protocol_test_fixture.py index ec6d7c7..1842df3 100644 --- a/test/protocol_test_fixture.py +++ b/test/protocol_test_fixture.py @@ -390,6 +390,29 @@ class BaseProtocolTest(unittest.TestCase): "Second ban should have been removed (different case)" ) + def test_parse_modes_channel_ban_cycle(self): + c = self.p.channels['#testruns'] = Channel(self.p, name='#testruns') + self.assertEqual( + self.p.parse_modes('#testruns', ['+b-b', '*!*@example.com', '*!*@example.com']), + [('+b', '*!*@example.com'), ('-b', '*!*@example.com')], + "Cycling a ban +b-b should remove it" + ) + self.assertEqual( + self.p.parse_modes('#testruns', ['-b+b', '*!*@example.com', '*!*@example.com']), + [('+b', '*!*@example.com')], + "Cycling a ban -b+b should add it" + ) + self.assertEqual( + self.p.parse_modes('#testruns', ['+b-b', '*!*@example.com', '*!*@Example.com']), + [('+b', '*!*@example.com'), ('-b', '*!*@example.com')], + "Cycling a ban +b-b should remove it (different case)" + ) + self.assertEqual( + self.p.parse_modes('#testruns', ['+b-b', '*!*@Example.com', '*!*@example.com']), + [('+b', '*!*@Example.com'), ('-b', '*!*@Example.com')], + "Cycling a ban +b-b should remove it (different case)" + ) + def test_parse_mode_channel_prefixmode_has_nick(self): c = self.p.channels['#'] = Channel(self.p, name='#') u = self._make_user('mynick', uid='myuid')