Hack 28 Automate Voice Management


abuse. Help prevent problems by creating a client script that is
responsible for handing out voice status to deserving
users. Let's
say you're the one in charge of managing a huge
channel that is dedicated to some important event
that's going on. Hundreds of people are joining and
leaving and, like any large channel, it will inevitably attract some
abusers as well, wanting to flood, swear, and spew out vile colorful
text.Your ban list is already full and a new horde of savages has just
entered the channel. What do you do? A simple step would be to
voice everyone as soon as they join the channel,
make the channel moderated, and just devoice the
user if he becomes abusive. The simple flaw here is that the evildoer
can part and rejoin the channel and get voiced.
|
and is implemented in Perl. It does not require any other modules and
needs no special configuration, so you simply have to place it into
your scripts directory (~/.irssi/scripts) and
perform /script load autovoice in order to get it
running.The script automatically voices every newcomer on the channel, so
make sure you have operator status on the channel or it
won't work. However, if anyone gets devoiced, the
script will remember this and save the host mask of the offender. If
the offender rejoins the channel, she will not get autovoiced again.
If anyone manually voices an offender, he will be removed from the
blacklist and will be autovoiced if he joins the channel at a later
moment. You can inspect the blacklist contents at any time by using
the /AUTOVOICE command.
4.13.1 The Code
This is a fairly simple irssi Perl hack, so the
comments in the code should explain what is going on. Every
irssi script should have an
%IRSSI hash that contains some basic information
and $VERSION that shows the current version number
of the script. Other scripts can then extract and use these pieces of
information automatically. A good example of this is
scriptassist.pl, which helps you manage your
scripts repository and interfaces the http://scripts.irssi.org central
irssi scripts repository. All good
irssi scripts should announce themselves when
they are loaded, just as ours politely does.
use strict;
use vars qw($VERSION %IRSSI);
use Irssi;
$VERSION = "0.0.1";
%IRSSI = (
name => 'autovoice',
authors => 'Petr Baudis',
contact => 'pasky@ucw.cz',
description => 'Smart voice management on a channel',
license => 'BSD',
);
# In this blacklist we keep all the offending hostmasks
# Keys: channels, Values: pointers to arrays of strings
my %dmasks;
# This command lists the blacklist's content
sub cmd_autovoice {
my ($data) = @_;
foreach my $chan (keys %dmasks) {
next unless ($dmasks{$chan});
my $str = "[$chan] ";
foreach my $mask (@{$dmasks{$chan}}) {
$str .= $mask . ", ";
}
$str =~ s/, $//;
Irssi::print($str);
}
}
# Triggered when someone joins a channel
sub event_massjoin {
my ($channel, $nicks_list) = @_;
my @nicks = @{$nicks_list};
return unless ($channel->{chanop});
# Each nick in a batch...
foreach my $nickrec (@nicks) {
my $in_blacklist = 0;
# Do we keep a blacklist for this channel?
if (defined $dmasks{$channel->{name}}) {
foreach my $mask (@{$dmasks{$channel->{name}}}) {
# Is this user blacklisted?
if ($channel->{server}->mask_match_address($mask, $nickrec->{nick},
$nickrec->{host})) {
$in_blacklist = 1; last;
}
}
}
$channel->command("/voice ".$nickrec->{nick}) unless $in_blacklist;
}
}
# Triggered when someone changes channel mode (including voice/devoice)
sub event_mode {
my ($server, $data, $nick, $addr) = @_;
my ($channel, @mmode) = split(/ /, $data);
my ($mode, @args) = @mmode;
my $operation;
my $chanptr = $server->channel_find($channel);
return if ($nick eq $server->{nick});
foreach my $mchar (split //, $mode) {
if ($mchar =~ /[+-]/) { $operation = $mchar; next; }
if ($mchar =~ /[eIbolk]/) { shift @args; }
if ($mchar ne 'v') { next; }
# This is a voice/devoice
my $victim = $args[0];
my $victptr = $chanptr->nick_find($victim);
if ($operation eq '+') {
if (defined $dmasks{$channel}) {
my @masks = @{$dmasks{$channel}};
for (my $i = 0; $i < @masks; $i++) {
if ($server->mask_match_address($masks[$i], $victim,
$victptr->{host})) {
splice(@masks, $i, 1);
$i--;
}
}
$dmasks{$channel} = \@masks;
}
} else {
my $in_blacklist = 1;
foreach my $mask (@{$dmasks{$channel}}) {
if ($server->mask_match_address($mask,
$victim, $victptr->{host})) {
$in_blacklist = 0; last;
}
}
push(@{$dmasks{$channel}}, $chanptr->ban_get_mask($victim, 0))
unless $in_blacklist;
}
}
}
Irssi::command_bind('autovoice', 'cmd_autovoice');
Irssi::signal_add_last('massjoin', 'event_massjoin');
Irssi::signal_add_last('event mode', 'event_mode');
Irssi::print "AutoVoice.PL $VERSION (c) Petr Baudis <pasky\@ucw.cz> loaded.";
4.13.2 Running the Hack
The script will be active as soon as it is loaded. You can load the
script by typing:
/script load autovoiceYou can then enjoy a sensible debate channel, without having to worry
about people ruining the karma.
4.13.3 Hacking the Hack
The main problem with the preceding
script is that its state is not persistent. This means that if you
restart irssi, the whole blacklist will be lost
and you are left starting from scratch. This is easy to
fixjust use the
Data::Dumper module and print
Dumper(\%dmasks) to a file each time you modify
the hash. If the file already exists at startup, you can load its
content into %dmasks.This hack was originally written for a single
irssi instance that is connected via a fast link
and acts only as a given channel's gatekeeper. If
you run it on multiple channels, the IRC session will start to get
much more vulnerable to lag, as voicing/devoicing on so many channels
will slow it down due to the rate limiting imposed by the IRC server.
If your irssi client is in multiple channels and
you would like to play gatekeeper on only one of them, you will need
to hack some settings to control that behavior into the previous
code. Also, if you are connected to multiple networks at the same
time and would like your script to work properly, you will need to
add support for multiple connections (for example, you could keep the
blacklist as a hash of hashes, indexed by the server tag first).It would also be good to have some way of manually editing the
blacklist, allowing you to add some more general host masks to it or
remove a good host mask. The script already provides a very simple
interface for displaying the blacklist contents, but improving this
is one thing you can experiment with. Petr Baudis