3
0
mirror of https://github.com/jlu5/PyLink.git synced 2024-12-25 04:02:45 +01:00

Add a 'massban' command

Closes #174.
This commit is contained in:
James Lu 2017-08-06 19:21:55 -07:00
parent 99790bfae2
commit d12f12ae22
2 changed files with 82 additions and 0 deletions

View File

@ -18,6 +18,7 @@ import ipaddress
import queue import queue
import functools import functools
import collections import collections
import string
try: try:
import ircmatch import ircmatch
@ -1074,6 +1075,31 @@ class PyLinkNetworkCoreWithUtils(PyLinkNetworkCore):
if self.match_host(banmask, uid) and uid in self.users: if self.match_host(banmask, uid) and uid in self.users:
yield uid yield uid
def make_channel_ban(self, uid, ban_type='ban'):
"""Creates a hostmask-based ban for the given user.
Ban exceptions, invite exceptions quiets, and extbans are also supported by setting ban_type
to the appropriate PyLink named mode (e.g. "ban", "banexception", "invex", "quiet", "ban_nonick")."""
assert uid in self.users, "Unknown user %s" % uid
# FIXME: verify that this is a valid mask.
# XXX: support slicing hosts so things like *!ident@*.isp.net are possible. This is actually
# more annoying to do than it appears because of vHosts using /, IPv6 addresses
# (cloaked and uncloaked), etc.
ban_style = self.serverdata.get('ban_style') or conf.conf['pylink'].get('ban_style') or \
'*!*@$host'
template = string.Template(ban_style)
banhost = template.safe_substitute(ban_style, **self.users[uid].__dict__)
assert utils.isHostmask(banhost), "Ban mask %r is not a valid hostmask!" % banhost
if ban_type in self.cmodes:
return ('+%s' % self.cmodes[ban_type], banhost)
elif ban_type in self.extbans_acting: # Handle extbans, which are generally "+b prefix:banmask"
return ('+%s' % self.cmodes['ban'], self.extbans_acting[ban_type]+banhost)
else:
raise ValueError("ban_type %r is not available on IRCd %r" % (ban_type, self.protoname))
def updateTS(self, sender, channel, their_ts, modes=None): def updateTS(self, sender, channel, their_ts, modes=None):
""" """
Merges modes of a channel given the remote TS and a list of modes. Merges modes of a channel given the remote TS and a list of modes.

View File

@ -67,6 +67,62 @@ def checkban(irc, source, args):
else: else:
irc.reply('No, \x02%s\x02 does not match \x02%s\x02.' % (args.target, args.banmask)) irc.reply('No, \x02%s\x02 does not match \x02%s\x02.' % (args.target, args.banmask))
massban_parser = utils.IRCParser()
massban_parser.add_argument('channel')
massban_parser.add_argument('banmask')
# Regarding default ban reason: it's a good idea not to leave in the caller to prevent retaliation...
massban_parser.add_argument('reason', nargs='*', default="Banned")
massban_parser.add_argument('--quiet', '-q', action='store_true')
def massban(irc, source, args):
"""<channel> <banmask / exttarget> [<kick reason>] [--quiet/-q]
Applies (i.e. kicks affected users) the given PyLink banmask on the specified channel.
The --quiet option can also be given to mass-mute the given user on networks where this is supported
(currently ts6, unreal, and inspircd). No kicks will be sent in this case."""
permissions.check_permissions(irc, source, ['opercmds.massban'])
args = massban_parser.parse_args(args)
if args.channel not in irc.channels:
irc.error("Unknown channel %r" % args.channel)
return
results = 0
for uid in irc.match_all(args.banmask, channel=args.channel):
# Remove the target's access before banning them.
bans = [('-%s' % irc.cmodes[prefix], uid) for prefix in irc.channels[args.channel].get_prefix_modes(uid) if prefix in irc.cmodes]
# Then, add the actual ban.
bans += [irc.make_channel_ban(uid, ban_type='quiet' if args.quiet else 'ban')]
irc.mode(irc.pseudoclient.uid, args.channel, bans)
try:
irc.call_hooks([irc.pseudoclient.uid, 'OPERCMDS_MASSBAN',
{'target': args.channel, 'modes': bans, 'parse_as': 'MODE'}])
except:
log.exception('(%s) Failed to send process massban hook; some bans may have not '
'been sent to plugins / relay networks!', irc.name)
if not args.quiet:
irc.kick(irc.pseudoclient.uid, args.channel, uid, args.reason)
# XXX: this better not be blocking...
try:
irc.call_hooks([irc.pseudoclient.uid, 'OPERCMDS_MASSKICK',
{'channel': args.channel, 'target': uid, 'text': args.reason, 'parse_as': 'KICK'}])
except:
log.exception('(%s) Failed to send process massban hook; some kicks may have not '
'been sent to plugins / relay networks!', irc.name)
results += 1
else:
irc.reply('Banned %s users on %r.' % (results, args.channel))
utils.add_cmd(massban, aliases=('mban',))
@utils.add_cmd @utils.add_cmd
def jupe(irc, source, args): def jupe(irc, source, args):
"""<server> [<reason>] """<server> [<reason>]