mirror of
https://github.com/Mikaela/Limnoria.git
synced 2024-11-30 06:49:24 +01:00
irclib: Fix support of power prefix chars in RPL_NAMREPLY
nickFromHostmask now (legitimately) complains when it's getting @ or ! at the beginning of a hostmask; so we need to strip them before passing it to nickFromHostmask. Then re-add them before calling c.addUser, because it uses them to sort users in the right sets (ops/halfops/voices). Additionally, this commit replaces the hardcoded set of prefix chars (`@%+&~!`) with the one advertised in ISUPPORT when possible.
This commit is contained in:
parent
aa6bd7257d
commit
d308329461
@ -389,15 +389,15 @@ class ChannelState(utils.python.Object):
|
|||||||
"""Returns whether the given nick is an halfop, or an op."""
|
"""Returns whether the given nick is an halfop, or an op."""
|
||||||
return nick in self.halfops or nick in self.ops
|
return nick in self.halfops or nick in self.ops
|
||||||
|
|
||||||
def addUser(self, user):
|
def addUser(self, user, prefix_chars='@%+&~!'):
|
||||||
"Adds a given user to the ChannelState. Power prefixes are handled."
|
"Adds a given user to the ChannelState. Power prefixes are handled."
|
||||||
nick = user.lstrip('@%+&~!')
|
nick = user.lstrip(prefix_chars)
|
||||||
if not nick:
|
if not nick:
|
||||||
return
|
return
|
||||||
# & is used to denote protected users in UnrealIRCd
|
# & is used to denote protected users in UnrealIRCd
|
||||||
# ~ is used to denote channel owner in UnrealIRCd
|
# ~ is used to denote channel owner in UnrealIRCd
|
||||||
# ! is used to denote protected users in UltimateIRCd
|
# ! is used to denote protected users in UltimateIRCd
|
||||||
while user and user[0] in '@%+&~!':
|
while user and user[0] in prefix_chars:
|
||||||
(marker, user) = (user[0], user[1:])
|
(marker, user) = (user[0], user[1:])
|
||||||
assert user, 'Looks like my caller is passing chars, not nicks.'
|
assert user, 'Looks like my caller is passing chars, not nicks.'
|
||||||
if marker in '@&~!':
|
if marker in '@&~!':
|
||||||
@ -963,13 +963,27 @@ class IrcState(IrcCommandDispatcher, log.Firewalled):
|
|||||||
if channel not in self.channels:
|
if channel not in self.channels:
|
||||||
self.channels[channel] = ChannelState()
|
self.channels[channel] = ChannelState()
|
||||||
c = self.channels[channel]
|
c = self.channels[channel]
|
||||||
|
|
||||||
|
# Set of prefixes servers may append before a NAMES reply when
|
||||||
|
# the user is op/halfop/voice/...
|
||||||
|
# https://datatracker.ietf.org/doc/html/draft-hardy-irc-isupport-00#section-4.15
|
||||||
|
prefix = self.supported.get('PREFIX')
|
||||||
|
if prefix is None:
|
||||||
|
prefix_chars = '@%+&~!' # see the comments in addUser
|
||||||
|
else:
|
||||||
|
prefix_chars = prefix.split(')', 1)[-1]
|
||||||
|
|
||||||
for item in items.split():
|
for item in items.split():
|
||||||
if ircutils.isUserHostmask(item):
|
stripped_item = item.lstrip(prefix_chars)
|
||||||
name = ircutils.nickFromHostmask(item)
|
item_prefix = item[0:-len(stripped_item)]
|
||||||
self.nicksToHostmasks[name] = name
|
if ircutils.isUserHostmask(stripped_item):
|
||||||
|
nick = ircutils.nickFromHostmask(stripped_item)
|
||||||
|
self.nicksToHostmasks[nick] = nick
|
||||||
|
name = item_prefix + nick
|
||||||
else:
|
else:
|
||||||
name = item
|
name = item
|
||||||
c.addUser(name)
|
c.addUser(name, prefix_chars=prefix_chars)
|
||||||
|
|
||||||
if type == '@':
|
if type == '@':
|
||||||
c.modes['s'] = None
|
c.modes['s'] = None
|
||||||
|
|
||||||
|
@ -529,6 +529,41 @@ class IrcStateTestCase(SupyTestCase):
|
|||||||
st = irclib.IrcState()
|
st = irclib.IrcState()
|
||||||
self.assert_(st.addMsg(self.irc, ircmsgs.IrcMsg('MODE foo +i')) or 1)
|
self.assert_(st.addMsg(self.irc, ircmsgs.IrcMsg('MODE foo +i')) or 1)
|
||||||
|
|
||||||
|
def testNamreply(self):
|
||||||
|
"""RPL_NAMREPLY / reply to NAMES"""
|
||||||
|
|
||||||
|
# Just nicks (à la RFC 1459 + some common prefix chars)
|
||||||
|
st = irclib.IrcState()
|
||||||
|
st.addMsg(self.irc, ircmsgs.IrcMsg(command='353',
|
||||||
|
args=('*', '=', '#chan', 'nick1 @nick2 ~@nick3')))
|
||||||
|
chan_st = st.channels['#chan']
|
||||||
|
self.assertEqual(chan_st.users, ircutils.IrcSet(['nick1', 'nick2', 'nick3']))
|
||||||
|
self.assertEqual(chan_st.ops, ircutils.IrcSet(['nick2', 'nick3']))
|
||||||
|
self.assertEqual(st.nicksToHostmasks, ircutils.IrcDict({}))
|
||||||
|
|
||||||
|
# with userhost-in-names
|
||||||
|
st = irclib.IrcState()
|
||||||
|
st.addMsg(self.irc, ircmsgs.IrcMsg(command='353',
|
||||||
|
args=('*', '=', '#chan', 'nick1!u1@h1 @nick2!u2@h2 ~@nick3!u3@h3')))
|
||||||
|
chan_st = st.channels['#chan']
|
||||||
|
self.assertEqual(chan_st.users, ircutils.IrcSet(['nick1', 'nick2', 'nick3']))
|
||||||
|
self.assertEqual(chan_st.ops, ircutils.IrcSet(['nick2', 'nick3']))
|
||||||
|
self.assertEqual(st.nicksToHostmasks['nick1'], 'nick1')
|
||||||
|
self.assertEqual(st.nicksToHostmasks['nick2'], 'nick2')
|
||||||
|
self.assertEqual(st.nicksToHostmasks['nick3'], 'nick3')
|
||||||
|
|
||||||
|
# Prefixed with chars not in ISUPPORT PREFIX
|
||||||
|
st = irclib.IrcState()
|
||||||
|
st.supported['PREFIX'] = '(ov)@+'
|
||||||
|
st.addMsg(self.irc, ircmsgs.IrcMsg(command='353',
|
||||||
|
args=('*', '=', '#chan', 'nick1!u1@h1 @nick2!u2@h2 ~@nick3!u3@h3')))
|
||||||
|
chan_st = st.channels['#chan']
|
||||||
|
self.assertEqual(chan_st.users, ircutils.IrcSet(['nick1', 'nick2', '~@nick3']))
|
||||||
|
self.assertEqual(chan_st.ops, ircutils.IrcSet(['nick2']))
|
||||||
|
self.assertEqual(st.nicksToHostmasks['nick1'], 'nick1')
|
||||||
|
self.assertEqual(st.nicksToHostmasks['nick2'], 'nick2')
|
||||||
|
self.assertEqual(st.nicksToHostmasks['~@nick3'], '~@nick3')
|
||||||
|
|
||||||
|
|
||||||
class IrcCapsTestCase(SupyTestCase, CapNegMixin):
|
class IrcCapsTestCase(SupyTestCase, CapNegMixin):
|
||||||
def testReqLineLength(self):
|
def testReqLineLength(self):
|
||||||
|
Loading…
Reference in New Issue
Block a user