#!/usr/bin/perl -w
# various kick and ban commands
# by c0ffee
# - http://www.penguin-breeder.org/irssi/
#
use vars qw($VERSION %IRSSI);
use Irssi 20020120;
$VERSION = "0.26";
%IRSSI = (
authors => "c0ffee",
contact => "c0ffee\@penguin-breeder.org",
name => "Various kick and ban commands",
description => "Enhances /k /kb and /kn with some nice options.",
license => "Public Domain",
url => "http://www.penguin-breeder.org/irssi/",
changed => "Tue Nov 14 23:19:19 CET 2006",
);
#
my %kickreasons = (
default => ["random kick victim",
"no thanks",
"on popular demand, you are now leaving the channel",
"\$N",
"/part is the command you're looking for",
"this is the irssi of borg. your mIRC will be assimilated. resistance is futile.",
"Autokick! mwahahahah!"
],
none => [""],
topic => ["\$topic"],
);
# fine tune the script for different chatnets
# cmdline_k regular expr that matches a correct cmdline for /k
# req_chan 0/1 whether the channel is always part of the cmdline
# num_nicks number of nicks ... (-1 = inf)
# start_with_dash 0/1 whether the normal cmdline may start with a dash
# match_chn matches channels
# match_n match nicks
# match_reason matches reasons
# default_reason reason to give as "no reason"
my %cfg = (
IRC => {
cmdline_k => '\s*([!#+&][^\x0\a\n\r ]*)\s+[-\[\]\\\\\`{}\w_|^\'~]+(,[-\[\]\\\\\`{}\w_|^\'~]+)*\s+\S.*',
req_chan => 0,
num_nicks => 3, # actually, /k takes more, but
# normal irc servers only take
# three in a row
start_with_dash => 1,
match_chn => '([!#+&][^\x0\a\n\r ]*)\s',
match_n => '(?:^|\s+)([-\[\]\\\\\`{}\w_|^\'~]+(?:,[-\[\]\\\\\`{}\w_|^\']+)*)',
match_reason => '^\s*[!#+&][^\x0\a\n\r ]*\s+[-\[\]\\\\\`{}\w_|^\'~]+(?:,[-\[\]\\\\\`{}\w_|^\'~]+)*\s+(\S.*)$',
default_reason => '$N'
},
SILC => {
cmdline_k => '\s*[^\x0-\x20\*\?,@!]+\s+[^\x0-\x20\*\?,@!]+\s+\S.*',
req_chan => 1,
num_nicks => 1,
start_with_dash => 0,
match_chn => '\s*([^\x0-\x20\*\?,@!]+)\s+[^\x0-\x20\*\?,@!]+(?:,[^\x0-\x20\*\?,@!]+)*',
match_n => '\s*(?:[^\x0-\x20\*\?,@!]+\s+)?([^\x0-\x20\*\?,@!]+(?:,[^\x0-\x20\*\?,@!]+)*)',
match_reason => '\s*[^\x0-\x20\*\?,@!]+\s+[^\x0-\x20\*\?,@!]+(?:,[^\x0-\x20\*\?,@!]+)*\s+(\S.*)',
default_reason => '$N'
}
);
sub initialize {
my $conf_file = Irssi::settings_get_str("kicks_configuration");
$conf_file =~ s/~/$ENV{HOME}/;
my ($basedir) = $conf_file =~ /^(.*\/).*?/;
if (-f $conf_file) {
open CONF, $conf_file;
while () {
$line++;
next if /^\s*#/;
chomp;
($key, $reasons) = /^(\S+)\s+(.+)\s*$/ or next;
if ($reasons =~ /\`([^\s]+).*?\`/) {
$kickreasons{$key} = "$reasons";
Irssi::print("Added executable $1 as $key...");
next;
}
$reasons =~ s/^"(.*)"$/$1/;
$reasons =~ s/~/$ENV{HOME}/;
$reasons =~ s/^([^\/])/$basedir$1/;
if (-f $reasons) {
$kickreasons{$key} = [];
open REASON, $reasons;
while () {
chomp;
push @{$kickreasons{$key}}, $_;
}
close REASON;
Irssi::print("Loaded $reasons as $key...");
} else {
Irssi::print("can't parse config line $line...");
}
}
close CONF;
} else {
Irssi::print("Could not find configuration file for kicks...");
Irssi::print("... use /set kicks_configuration ");
}
}
sub get_a_reason {
my ($topic) = @_;
return "" if not defined $kickreasons{$topic};
$_ = eval $kickreasons{$topic}, chomp, s/[\n\t]+/ /mg, return $_
if ref($kickreasons{$topic}) ne "ARRAY";
return $kickreasons{$topic}[rand @{$kickreasons{$topic}}];
}
sub cmd_realkick {
my ($data, $server, $channel, $cmd) = @_;
my $reasons = "default";
return if not $server
or not defined $cfg{$server->{chat_type}}
or not $channel
or $data =~ /^$cfg{$server->{chat_type}}{cmdline_k}$/;
Irssi::signal_stop();
# let's see whether some options where supplied
$default = Irssi::settings_get_str("default_kick_options");
$data = "$default $data" if not $default =~ /^\s*$/;
@opts = split /\s+/, $data;
while (($opt) = (shift @opts) =~ /^\s*-(\S+)/) {
$data =~ s/^\s*--\s+//, last if $opt eq "-";
$data =~ s/^\s*-$opt\s+//,
$reasons = lc $opt,
next if defined $kickreasons{lc $opt};
last if $cfg{$server->{chat_type}}{start_with_dash};
Irssi::print("Unknown option -$opt");
$fail = true;
}
return if $fail;
$chn = "";
($chn) = $data =~ /^$cfg{$server->{chat_type}}{match_chn}/;
if ($cfg{$server->{chat_type}}{req_chan} && ($chn eq "")) {
Irssi::print "Not joined to any channel";
return;
}
# do we need to add a channel?
if ($chn eq "") {
Irssi::print("Not joined to any channel"), return
if $channel->{type} ne "CHANNEL";
$chn = $channel->{name};
$data = "$chn $data";
}
# is a reason already supplied?
$reason = get_a_reason($reasons)
if not (($reason) = $data =~ /$cfg{$server->{chat_type}}{match_reason}/);
$reason = $cfg{$server->{chat_type}}{default_reason}
if $reason =~ /^\s*$/;
@nicks = split /,/, ($data =~ /$cfg{$server->{chat_type}}{match_n}/)[0];
$num_nicks = $cfg{$server->{chat_type}}{num_nicks};
$num_nicks = @nicks if $num_nicks <= 0;
undef @commands;
while (@nicks) {
$tmp = ($chn ne "" ? "$chn " : "") .
join ",", (splice @nicks,0,$num_nicks);
$tmp =~ s/([;\\\$])/\\$1/g;
push @commands, "$tmp $reason";
}
foreach (@commands) {
if ($_ =~ /^$cfg{$server->{chat_type}}{cmdline_k}$/) {
s/\s+$//;
$channel->command("EVAL $cmd $_")
} else {
Irssi::print("BUG: generated invalid $cmd command: $_");
}
}
}
sub cmd_kick {
my ($data, $server, $channel) = @_;
cmd_realkick $data, $server, $channel, "KICK";
}
sub cmd_kickban {
my ($data, $server, $channel) = @_;
cmd_realkick $data, $server, $channel, "KICKBAN";
}
Irssi::settings_add_str("misc", "default_kick_options", "");
Irssi::settings_add_str("misc", "kicks_configuration",
Irssi::get_irssi_dir() . "/kicks.conf");
Irssi::command_bind("kick", "cmd_kick");
Irssi::command_bind("kickban", "cmd_kickban");
initialize();