diff --git a/plugins/AutoMode/plugin.py b/plugins/AutoMode/plugin.py index 738aae428..a3e8db67c 100644 --- a/plugins/AutoMode/plugin.py +++ b/plugins/AutoMode/plugin.py @@ -163,7 +163,8 @@ class AutoMode(callbacks.Plugin): # We're not in the channel anymore. pass schedule.addEvent(unban, time.time()+period) - banmask =conf.supybot.protocols.irc.banmask.makeBanmask(msg.prefix) + banmask = conf.supybot.protocols.irc.banmask.makeExtBanmask( + msg.prefix, channel=channel, network=irc.network) irc.queueMsg(ircmsgs.ban(channel, banmask)) irc.queueMsg(ircmsgs.kick(channel, msg.nick)) diff --git a/plugins/Channel/plugin.py b/plugins/Channel/plugin.py index e6d24fcae..815a1ef18 100644 --- a/plugins/Channel/plugin.py +++ b/plugins/Channel/plugin.py @@ -368,7 +368,9 @@ class Channel(callbacks.Plugin): try: bannedHostmask = irc.state.nickToHostmask(target) banmaskstyle = conf.supybot.protocols.irc.banmask - banmask = banmaskstyle.makeBanmask(bannedHostmask, [o[0] for o in optlist]) + banmask = banmaskstyle.makeExtBanmask( + bannedHostmask, [o[0] for o in optlist], + channel=channel, network=irc.network) except KeyError: if not conf.supybot.protocols.irc.strictRfc() and \ target.startswith('$'): @@ -606,7 +608,9 @@ class Channel(callbacks.Plugin): c.addBan(banmask, expires) ircdb.channels.setChannel(channel, c) irc.replySuccess() - add = wrap(add, ['op', first('hostmask', 'banmask'), additional('expiry', 0)]) + add = wrap(add, ['op', + first('hostmask', 'extbanmask'), + additional('expiry', 0)]) @internationalizeDocstring def remove(self, irc, msg, args, channel, banmask): diff --git a/plugins/Channel/test.py b/plugins/Channel/test.py index f091cae88..35b71c3c8 100644 --- a/plugins/Channel/test.py +++ b/plugins/Channel/test.py @@ -273,14 +273,24 @@ class ChannelTestCase(ChannelPluginTestCase): self.channel, prefix='foobar!user@host.domain.tld')) join() self.irc.feedMsg(ircmsgs.op(self.channel, self.irc.nick)) - self.assertKban('kban --account --exact foobar', - '~a:account1') - join() - self.assertKban('kban --account foobar', - '~a:account1') - join() - self.assertKban('kban --account --host foobar', - '~a:account1') + + + for style in (['exact'], ['account', 'exact']): + with conf.supybot.protocols.irc.banmask.context(style): + self.assertKban('kban --account --exact foobar', + '~a:account1') + join() + self.assertKban('kban --account foobar', + '~a:account1') + join() + self.assertKban('kban --account --host foobar', + '~a:account1') + join() + + with conf.supybot.protocols.irc.banmask.context(['account', 'exact']): + self.assertKban('kban foobar', + '~a:account1') + join() def testBan(self): with conf.supybot.protocols.irc.banmask.context(['exact']): diff --git a/src/commands.py b/src/commands.py index f93e7ce47..2874c4692 100644 --- a/src/commands.py +++ b/src/commands.py @@ -435,7 +435,14 @@ def getBanmask(irc, msg, args, state): getChannel(irc, msg, args, state) banmaskstyle = conf.supybot.protocols.irc.banmask state.args[-1] = banmaskstyle.makeBanmask(state.args[-1], - channel=state.channel) + channel=state.channel, network=irc.network) + +def getExtBanmask(irc, msg, args, state): + getHostmask(irc, msg, args, state) + getChannel(irc, msg, args, state) + banmaskstyle = conf.supybot.protocols.irc.extbanmask + state.args[-1] = banmaskstyle.makeExtBanmask(state.args[-1], + channel=state.channel, network=irc.network) def getUser(irc, msg, args, state): try: @@ -806,6 +813,7 @@ wrappers = ircutils.IrcDict({ 'commandName': getCommandName, 'email': getEmail, 'expiry': getExpiry, + 'extbanmask': getExtBanmask, 'filename': getSomething, # XXX Check for validity. 'float': getFloat, 'glob': getGlob, diff --git a/src/conf.py b/src/conf.py index 2848d817d..975852c34 100644 --- a/src/conf.py +++ b/src/conf.py @@ -1181,7 +1181,7 @@ registerGroup(supybot.protocols, 'irc') class Banmask(registry.SpaceSeparatedSetOfStrings): __slots__ = ('__parent', '__dict__') # __dict__ is needed to set __doc__ - validStrings = ('exact', 'nick', 'user', 'host') + validStrings = ('exact', 'nick', 'user', 'host', 'account') def __init__(self, *args, **kwargs): assert self.validStrings, 'There must be some valid strings. ' \ 'This is a bug.' @@ -1215,6 +1215,31 @@ class Banmask(registry.SpaceSeparatedSetOfStrings): isn't specified via options, the value of conf.supybot.protocols.irc.banmask is used. + Unlike :meth:`makeExtBanmask`, this is guaranteed to return an + RFC1459-like mask, suitable for ircdb's ignore lists. + + options - A list specifying which parts of the hostmask should + explicitly be matched: nick, user, host. If 'exact' is given, then + only the exact hostmask will be used. + """ + if not network: + network = dynamic.irc.network + if not options: + options = supybot.protocols.irc.banmask.getSpecific( + network, channel)() + options = [option for option in options if option != 'account'] + return self.makeExtBanmask(hostmask, options, channel, network=network) + + def makeExtBanmask(self, hostmask, options=None, channel=None, *, network): + """Create a banmask from the given hostmask. If a style of banmask + isn't specified via options, the value of + conf.supybot.protocols.irc.banmask is used. + + Depending on the options and configuration, this may return a mask + in the format of an extban (eg. "~account:foobar" on UnrealIRCd). + If this is unwanted (eg. to pass to ircdb's ignore lists, use + :meth:`makeBanmask` instead) + options - A list specifying which parts of the hostmask should explicitly be matched: nick, user, host. If 'exact' is given, then only the exact hostmask will be used. @@ -1224,8 +1249,6 @@ class Banmask(registry.SpaceSeparatedSetOfStrings): """ if not channel: channel = dynamic.channel - if not network: - network = dynamic.irc.network (nick, user, host) = ircutils.splitHostmask(hostmask) bnick = '*' buser = '*'