# bleh stuff
use Irssi;
use Irssi::Irc;
use strict;
use vars qw($VERSION %IRSSI $DEBUG);
# 0.05 -- Add IPv6 support
$VERSION = q$Revision: 1.1 $;
%IRSSI = (authors => 'Don Armstrong',
name => 'auto_bleh',
description => 'Provides /ak /aq /ab /abr /abrn /arn /amb /amr /at',
license => 'GPL',
changed => q$Id: auto_bleh.pl,v 1.1 2005/03/17 08:19:53 don Exp $,
);
$DEBUG = 1 unless defined $DEBUG;
my ($actions, %defaults);
%defaults = (GET_OP => 1, # Should we try to get opped when we auto_bleh?
USE_CHANSERV => 1, # Should we use chanserv to get opped?
EXPIRE => 6000, # Do not try to do anything if the action is more than 6000 seconds old.
DEOP => 1, # Automatically deop after we've done whatever we were supposed to do.
TIMEOUT => 10, # Timeout /at bans after 10 minutes
);
my %command_bindings = (ak => 'cmd_ak',
ab => 'cmd_ab',
aq => 'cmd_aq',
ar => 'cmd_ar',
abr => 'cmd_abr',
abk => 'cmd_abk',
abrn => 'cmd_abrn',
abk => 'cmd_abkn',
arn => 'cmd_arn',
amb => 'cmd_amb',
amr => 'cmd_amr',
at => 'cmd_at',
);
my %bans_to_remove;
sub cmd_at {
my ($data, $server, $witem) = @_;
return do_auto_bleh('timeout',$data,$server,$witem);
}
sub cmd_ak {
my ($data, $server, $witem) = @_;
return do_auto_bleh('kick',$data,$server,$witem);
}
sub cmd_abk {
my ($data, $server, $witem) = @_;
return do_auto_bleh('kick,ban',$data,$server,$witem);
}
sub cmd_abkn {
my ($data, $server, $witem) = @_;
return do_auto_bleh('kick,ban,notice',$data,$server,$witem);
}
sub cmd_amb{
my ($data, $server, $witem) = @_;
my @nicks = split /\s+/, $data;
for (@nicks) {
next unless /\w/;
do_auto_bleh('ban',$_,$server,$witem);
}
}
sub cmd_ab {
my ($data, $server, $witem) = @_;
return do_auto_bleh('ban',$data,$server,$witem);
}
sub cmd_aq {
my ($data, $server, $witem) = @_;
return do_auto_bleh('quiet',$data,$server,$witem);
}
sub cmd_amr{
my ($data, $server, $witem) = @_;
my @nicks = split /\s+/, $data;
for (@nicks) {
next unless /\w/;
do_auto_bleh('remove',$_,$server,$witem);
}
}
sub cmd_ar {
my ($data, $server, $witem) = @_;
return do_auto_bleh('remove',$data,$server,$witem);
}
sub cmd_abr{
my ($data, $server, $witem) =@_;
return do_auto_bleh('remove,ban',$data,$server,$witem);
}
sub cmd_abrn{
my ($data, $server, $witem) =@_;
return do_auto_bleh('remove,ban,notice',$data,$server,$witem);
}
sub cmd_arn{
my ($data, $server, $witem) =@_;
return do_auto_bleh('remove,notice',$data,$server,$witem);
}
sub do_auto_bleh {
my ($cmd, $data, $server, $witem, $duration) = @_;
if (!$server || !$server->{connected}) {
Irssi::print("Not connected to server");
return;
}
if ($witem->{type} ne 'CHANNEL') {
Irssi::print("Can't autokick on a non-channel. [$witem->{type}]");
return;
}
# use Data::Dumper;
# Irssi::print(Dumper($data,$server,$witem));
# set the network that we're on, the channel and the nick to kick
# once we've been opped
# Heh. Looks like $data needs to be sanitized a bit.
$data =~ /^\s*([^\s]+)\s*(\d+)?\s*(.+?|)\s*$/;
my $nick = $1;
my $timeout = $2;
my $reason = $3;
$timeout = $defaults{TIMEOUT} if not defined $timeout or $timeout eq '';
$reason = 'you should know better' if not defined $reason or $reason eq '';
my $nick_rec = $witem->nick_find($nick);
if (not defined $nick_rec) {
Irssi::print("Unable to find nick: $nick");
}
my $hostname = $nick_rec->{host} if defined $nick_rec;
Irssi::print("Unable to find hostname for $nick") if not defined $hostname or $hostname eq '';
$hostname =~ s/.+\@//;
Irssi::print("Nick set to '$nick' from '$data', reason set to '$reason'.") if $DEBUG;
my $action = {type => $cmd,
nick => $nick,
nick_rec => $nick_rec,
network => $witem->{server}->{chatnet},
server => $witem->{server},
completed => 0,
inserted => time,
channel => $witem->{name},
reason => $reason,
hostname => $hostname,
timeout => $timeout,
};
Irssi::print(i_want($action)) if $DEBUG;
if ($witem->{chanop}) { # we seem to be opped.
take_action($action,$server,$witem);
}
else {
$actions->{$data.$action->{inserted}}=$action;
get_op($server, $action->{channel}) if $defaults{GET_OP};
}
}
sub get_op {
my ($server,$channel) = @_;
Irssi::print("MSG chanserv op $channel");
$server->command("MSG chanserv op $channel") if $defaults{USE_CHANSERV};
}
sub i_want {
my $action = shift;
return "I've wanted to $action->{type} $action->{nick} off $action->{channel} on $action->{network} since $action->{inserted}";
}
sub take_action {
my ($action,$server,$channel) = @_;
local $_ = $action->{type};
# Now support multiple actions against a single nick (to FE, kick
# ban, or remove ban). See /abr foo
if (/timeout/) {
Irssi::print("Quieting $action->{nick} on $action->{channel} with hostname $action->{hostname} for $action->{timeout} minutes");
$channel->command("/quote MODE $action->{channel} +q *!*@".$action->{hostname}) if $action->{hostname} ne ''; #quiet hostname
$bans_to_remove{"$action->{nick}$action->{inserted}"} = $action;
}
if (/quiet/) {
Irssi::print("Quieting $action->{nick} on $action->{channel} with hostname $action->{hostname}") if $DEBUG;
# Find hostname
$channel->command("/quote MODE $action->{channel} +q *!*@".$action->{hostname}) if $action->{hostname} ne ''; #quiet hostname
}
if (/ban/) {
Irssi::print("Banning $action->{nick} from $action->{channel} with hostname $action->{hostname}") if $DEBUG;
$channel->command("/quote MODE $action->{channel} +b *!*@".$action->{hostname}) if $action->{hostname} ne ''; # ban hostname
}
if (/kick/) {
Irssi::print("Kicking $action->{nick} from $action->{channel}") if $DEBUG;
if ($action->{reason} =~ /\s/) {
$channel->command("/quote KICK $action->{channel} $action->{nick} :$action->{reason}");
}
else {
$channel->command("/quote REMOVE $action->{channel} $action->{nick} $action->{reason}");
}
}
if (/remove/) {
Irssi::print("Removing $action->{nick} from $action->{channel}") if $DEBUG;
if ($action->{reason} =~ /\s/) {
$channel->command("/quote REMOVE $action->{channel} $action->{nick} :$action->{reason}");
}
else {
$channel->command("/quote REMOVE $action->{channel} $action->{nick} $action->{reason}");
}
}
if (/notice/) {
Irssi::print("Noticing $action->{nick} with $action->{reason}") if $DEBUG;
$channel->command("/NOTICE $action->{nick} $action->{reason}");
}
# unquiet. This is crap, and needs to be changed to something sane.
if (/teiuq/) {
Irssi::print("Unquieting $action->{nick} on $action->{channel} with hostname $action->{hostname}") if $DEBUG;
$channel->command("/quote MODE $action->{channel} -q *!*@".$action->{hostname});
}
return; #for now.
}
sub deop_us {
my ($rec) = @_;
my $channel = $rec->{channel};
my $server = $rec->{server};
#$server->command("MODE $channel->{name} -o $channel->{ownick}->{nick}");
#if ($channel->{chanop}) {
Irssi::print("MODE $channel->{name} -o $channel->{ownnick}->{nick}");
$channel->command("/deop $channel->{ownnick}->{nick}");
#}
}
sub sig_mode_change {
my ($channel,$nick) = @_;
#Irssi::print(Dumper($nick));
#Irssi::print(Dumper($channel));
# Are there any actions to process?
# See if we got opped.
return if scalar(keys %$actions) eq 0;
my @deop_array;
if ($channel->{server}->{nick} eq $nick->{nick} and $nick->{op}) {
# Ok, we've been opped, or we are opped now, so do whatever we're supposed to do.
Irssi::print("We've been opped") if $DEBUG;
foreach (keys %$actions) {
#Irssi::print(Dumper($actions->{$_}));
# See if this action is too old
if (time - $actions->{$_}->{inserted} > $defaults{EXPIRE}) {
Irssi::print("Expiring action: \"".i_want($actions->{$_})."\" because of time");
delete $actions->{$_};
next;
}
Irssi::print(i_want($actions->{$_})) if $DEBUG;
# Find the server to take action on
#my $server = Irssi::server_find_chatnet($actions->{$_}->{network});
my $server = $actions->{$_}->{server};
Irssi::print("Unable to find server for chatnet: $actions->{$_}->{network}") and return if not defined $server;
Irssi::print("Found server for chatnet: $actions->{$_}->{network}") if $DEBUG;
# Find the channel to take action on
my $channel = $server->channel_find($actions->{$_}->{channel});
Irssi::print("Unable to find channel for channel: $actions->{$_}->{channel}") and return if not defined $channel;
Irssi::print("Found channel for channel: $actions->{$_}->{channel}") if $DEBUG;
# Are we opped on that channel?
#if ($channel->{chanop}) { # Yes? Take the action against the user.
Irssi::print("We are opped on the channel!") if $DEBUG;
take_action($actions->{$_},$server,$channel);
push @deop_array,{server=>$server,channel=>$channel} if $defaults{DEOP};
delete $actions->{$_}; # Do not repeat this action.
#}
#else {
# Irssi::print("We are not opped on the channel.") if $DEBUG;
#}
}
foreach (@deop_array) {
deop_us($_);
}
}
else {
Irssi::print("Fooey. Not opped.") if $DEBUG;
}
}
sub try_to_remove_bans {
return unless keys %bans_to_remove;
for my $key (keys %bans_to_remove) {
if (($bans_to_remove{$key}{inserted} + $bans_to_remove{$key}{timeout}*60) < time) {
$bans_to_remove{$key}{type} = 'teiuq'; #unquiet
$actions->{$key} = $bans_to_remove{$key};
delete $bans_to_remove{$key};
get_op($actions->{$key}{server}, $actions->{$key}{channel}) if $defaults{GET_OP};
}
}
}
# call the try to remove bans function every minute
Irssi::timeout_add(1000*60,'try_to_remove_bans',undef);
Irssi::signal_add_last('nick mode changed','sig_mode_change');
my ($command,$function);
while (($command,$function) = each %command_bindings) {
Irssi::command_bind($command,$function);
}
1;