mirror of
https://github.com/pragma-/pbot.git
synced 2024-11-20 02:49:49 +01:00
eb8a49cc74
Instead of only taking a hostmask argument, `unban` will now determine if the argument is a nick, and if so it will then find all bans that match various hostmasks used by that nick and unban them all.
300 lines
8.8 KiB
Perl
300 lines
8.8 KiB
Perl
# File: ChanOps.pm
|
|
# Author: pragma_
|
|
#
|
|
# Purpose: Provides channel operator status tracking and commands.
|
|
|
|
package PBot::ChanOps;
|
|
|
|
use warnings;
|
|
use strict;
|
|
|
|
use PBot::ChanOpCommands;
|
|
use Time::HiRes qw(gettimeofday);
|
|
|
|
sub new {
|
|
if(ref($_[1]) eq 'HASH') {
|
|
Carp::croak("Options to " . __FILE__ . " should be key/value pairs, not hash reference");
|
|
}
|
|
|
|
my ($class, %conf) = @_;
|
|
my $self = bless {}, $class;
|
|
$self->initialize(%conf);
|
|
return $self;
|
|
}
|
|
|
|
sub initialize {
|
|
my ($self, %conf) = @_;
|
|
|
|
$self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to ChanOps");
|
|
|
|
$self->{unban_timeout} = PBot::DualIndexHashObject->new(
|
|
pbot => $self->{pbot},
|
|
name => 'Unban Timeouts',
|
|
filename => $self->{pbot}->{registry}->get_value('general', 'data_dir') . '/unban_timeouts'
|
|
);
|
|
|
|
$self->{unban_timeout}->load;
|
|
|
|
$self->{unmute_timeout} = PBot::DualIndexHashObject->new(
|
|
pbot => $self->{pbot},
|
|
name => 'Unmute Timeouts',
|
|
filename => $self->{pbot}->{registry}->get_value('general', 'data_dir') . '/unmute_timeouts'
|
|
);
|
|
|
|
$self->{unmute_timeout}->load;
|
|
|
|
$self->{op_commands} = {};
|
|
$self->{is_opped} = {};
|
|
$self->{op_requested} = {};
|
|
|
|
$self->{commands} = PBot::ChanOpCommands->new(pbot => $self->{pbot});
|
|
|
|
$self->{pbot}->{registry}->add_default('text', 'general', 'deop_timeout', $conf{'deop_timeout'} // 300);
|
|
|
|
$self->{pbot}->{timer}->register(sub { $self->check_opped_timeouts }, 10);
|
|
$self->{pbot}->{timer}->register(sub { $self->check_unban_timeouts }, 10);
|
|
$self->{pbot}->{timer}->register(sub { $self->check_unmute_timeouts }, 10);
|
|
}
|
|
|
|
sub can_gain_ops {
|
|
my ($self, $channel) = @_;
|
|
return exists $self->{pbot}->{channels}->{channels}->hash->{$channel} && $self->{pbot}->{channels}->{channels}->hash->{$channel}{chanop};
|
|
}
|
|
|
|
sub gain_ops {
|
|
my $self = shift;
|
|
my $channel = shift;
|
|
|
|
return if exists $self->{op_requested}->{$channel};
|
|
return if not $self->can_gain_ops($channel);
|
|
|
|
if(not exists $self->{is_opped}->{$channel}) {
|
|
$self->{pbot}->{conn}->privmsg("chanserv", "op $channel");
|
|
$self->{op_requested}->{$channel} = scalar gettimeofday;
|
|
} else {
|
|
$self->perform_op_commands($channel);
|
|
}
|
|
}
|
|
|
|
sub lose_ops {
|
|
my $self = shift;
|
|
my $channel = shift;
|
|
$self->{pbot}->{conn}->privmsg("chanserv", "op $channel -" . $self->{pbot}->{registry}->get_value('irc', 'botnick'));
|
|
}
|
|
|
|
sub add_op_command {
|
|
my ($self, $channel, $command) = @_;
|
|
return if not $self->can_gain_ops($channel);
|
|
push @{ $self->{op_commands}->{$channel} }, $command;
|
|
}
|
|
|
|
sub perform_op_commands {
|
|
my $self = shift;
|
|
my $channel = shift;
|
|
my $botnick = $self->{pbot}->{registry}->get_value('irc', 'botnick');
|
|
|
|
$self->{pbot}->{logger}->log("Performing op commands...\n");
|
|
while(my $command = shift @{ $self->{op_commands}->{$channel} }) {
|
|
if($command =~ /^mode (.*?) (.*)/i) {
|
|
$self->{pbot}->{conn}->mode($1, $2);
|
|
$self->{pbot}->{logger}->log(" executing mode [$1] [$2]\n");
|
|
} elsif($command =~ /^kick (.*?) (.*?) (.*)/i) {
|
|
$self->{pbot}->{conn}->kick($1, $2, $3) unless $1 =~ /\Q$botnick\E/i;
|
|
$self->{pbot}->{logger}->log(" executing kick on $1 $2 $3\n");
|
|
}
|
|
}
|
|
$self->{pbot}->{logger}->log("Done.\n");
|
|
}
|
|
|
|
sub ban_user {
|
|
my $self = shift;
|
|
my ($mask, $channel) = @_;
|
|
|
|
$self->add_op_command($channel, "mode $channel +b $mask");
|
|
$self->gain_ops($channel);
|
|
}
|
|
|
|
sub unban_user {
|
|
my $self = shift;
|
|
my ($mask, $channel) = @_;
|
|
|
|
my $bans;
|
|
|
|
if ($mask !~ m/[!@]/) {
|
|
my ($message_account, $hostmask) = $self->{pbot}->{messagehistory}->{database}->find_message_account_by_nick($mask);
|
|
|
|
if (defined $hostmask) {
|
|
$bans = $self->{pbot}->{bantracker}->get_baninfo($hostmask, $channel);
|
|
}
|
|
}
|
|
|
|
if (not defined $bans) {
|
|
my $baninfo = {};
|
|
$baninfo->{banmask} = $mask;
|
|
push @$bans, $baninfo;
|
|
}
|
|
|
|
foreach my $baninfo (@$bans) {
|
|
$self->{pbot}->{logger}->log("Unbanning $channel $baninfo->{banmask}\n");
|
|
if($self->{unban_timeout}->find_index($channel, $baninfo->{banmask})) {
|
|
$self->{unban_timeout}->hash->{$channel}->{$baninfo->{banmask}}{timeout} = gettimeofday + 7200; # try again in 2 hours if unban doesn't immediately succeed
|
|
$self->{unban_timeout}->save;
|
|
}
|
|
$self->add_op_command($channel, "mode $channel -b $baninfo->{banmask}");
|
|
}
|
|
$self->gain_ops($channel);
|
|
}
|
|
|
|
sub ban_user_timed {
|
|
my $self = shift;
|
|
my ($mask, $channel, $length) = @_;
|
|
|
|
$mask .= '!*@*' if $mask !~ m/[\$!@]/;
|
|
$self->ban_user($mask, $channel);
|
|
if ($length > 0) {
|
|
$self->{unban_timeout}->hash->{$channel}->{$mask}{timeout} = gettimeofday + $length;
|
|
$self->{unban_timeout}->save;
|
|
} else {
|
|
if ($self->{pbot}->{chanops}->{unban_timeout}->find_index($channel, $mask)) {
|
|
$self->{pbot}->{chanops}->{unban_timeout}->remove($channel, $mask);
|
|
}
|
|
}
|
|
}
|
|
|
|
sub mute_user {
|
|
my $self = shift;
|
|
my ($mask, $channel) = @_;
|
|
|
|
$self->add_op_command($channel, "mode $channel +q $mask");
|
|
$self->gain_ops($channel);
|
|
}
|
|
|
|
sub unmute_user {
|
|
my $self = shift;
|
|
my ($mask, $channel) = @_;
|
|
$self->{pbot}->{logger}->log("Unmuting $channel $mask\n");
|
|
if($self->{unmute_timeout}->find_index($channel, $mask)) {
|
|
$self->{unmute_timeout}->hash->{$channel}->{$mask}{timeout} = gettimeofday + 7200; # try again in 2 hours if unmute doesn't immediately succeed
|
|
$self->{unmute_timeout}->save;
|
|
}
|
|
$self->add_op_command($channel, "mode $channel -q $mask");
|
|
$self->gain_ops($channel);
|
|
}
|
|
|
|
sub mute_user_timed {
|
|
my $self = shift;
|
|
my ($mask, $channel, $length) = @_;
|
|
|
|
$mask .= '!*@*' if $mask !~ m/[\$!@]/;
|
|
$self->mute_user($mask, $channel);
|
|
if ($length > 0) {
|
|
$self->{unmute_timeout}->hash->{$channel}->{$mask}{timeout} = gettimeofday + $length;
|
|
$self->{unmute_timeout}->save;
|
|
} else {
|
|
if ($self->{pbot}->{chanops}->{unmute_timeout}->find_index($channel, $mask)) {
|
|
$self->{pbot}->{chanops}->{unmute_timeout}->remove($channel, $mask);
|
|
}
|
|
}
|
|
}
|
|
|
|
sub join_channel {
|
|
my ($self, $channels) = @_;
|
|
|
|
$self->{pbot}->{conn}->join($channels);
|
|
|
|
foreach my $channel (split /,/, $channels) {
|
|
$self->{pbot}->{event_dispatcher}->dispatch_event('pbot.join', { channel => $channel });
|
|
|
|
delete $self->{is_opped}->{$channel};
|
|
delete $self->{op_requested}->{$channel};
|
|
|
|
if (exists $self->{pbot}->{channels}->{channels}->hash->{$channel}
|
|
and exists $self->{pbot}->{channels}->{channels}->hash->{$channel}{permop}
|
|
and $self->{pbot}->{channels}->{channels}->hash->{$channel}{permop}) {
|
|
$self->gain_ops($channel);
|
|
}
|
|
}
|
|
}
|
|
|
|
sub part_channel {
|
|
my ($self, $channel) = @_;
|
|
|
|
$self->{pbot}->{event_dispatcher}->dispatch_event('pbot.part', { channel => $channel });
|
|
$self->{pbot}->{conn}->part($channel);
|
|
|
|
delete $self->{is_opped}->{$channel};
|
|
delete $self->{op_requested}->{$channel};
|
|
}
|
|
|
|
sub has_ban_timeout {
|
|
my ($self, $channel, $mask) = @_;
|
|
return exists $self->{unban_timeout}->hash->{$channel}->{$mask};
|
|
}
|
|
|
|
sub has_mute_timeout {
|
|
my ($self, $channel, $mask) = @_;
|
|
return exists $self->{unmute_timeout}->hash->{$channel}->{$mask};
|
|
}
|
|
|
|
|
|
sub check_unban_timeouts {
|
|
my $self = shift;
|
|
|
|
return if not $self->{pbot}->{joined_channels};
|
|
|
|
my $now = gettimeofday();
|
|
|
|
foreach my $channel (keys %{ $self->{unban_timeout}->hash }) {
|
|
foreach my $mask (keys %{ $self->{unban_timeout}->hash->{$channel} }) {
|
|
if($self->{unban_timeout}->hash->{$channel}->{$mask}{timeout} < $now) {
|
|
$self->unban_user($mask, $channel);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
sub check_unmute_timeouts {
|
|
my $self = shift;
|
|
|
|
return if not $self->{pbot}->{joined_channels};
|
|
|
|
my $now = gettimeofday();
|
|
|
|
foreach my $channel (keys %{ $self->{unmute_timeout}->hash }) {
|
|
foreach my $mask (keys %{ $self->{unmute_timeout}->hash->{$channel} }) {
|
|
if($self->{unmute_timeout}->hash->{$channel}->{$mask}{timeout} < $now) {
|
|
$self->unmute_user($mask, $channel);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
sub check_opped_timeouts {
|
|
my $self = shift;
|
|
my $now = gettimeofday();
|
|
|
|
foreach my $channel (keys %{ $self->{is_opped} }) {
|
|
if($self->{is_opped}->{$channel}{timeout} < $now) {
|
|
unless (exists $self->{pbot}->{channels}->{channels}->hash->{$channel}
|
|
and exists $self->{pbot}->{channels}->{channels}->hash->{$channel}{permop}
|
|
and $self->{pbot}->{channels}->{channels}->hash->{$channel}{permop}) {
|
|
$self->lose_ops($channel);
|
|
delete $self->{is_opped}->{$channel}; # assume chanserv is alive and deop will succeed
|
|
}
|
|
} else {
|
|
# my $timediff = $self->{is_opped}->{$channel}{timeout} - $now;
|
|
# $self->{pbot}->{logger}->log("deop $channel in $timediff seconds\n");
|
|
}
|
|
}
|
|
|
|
foreach my $channel (keys %{ $self->{op_requested} }) {
|
|
if ($now - $self->{op_requested}->{$channel} > 60 * 5) {
|
|
$self->{pbot}->{logger}->log("5 minutes since OP request for $channel and no OP yet; trying again ...\n");
|
|
delete $self->{op_requested}->{$channel};
|
|
$self->gain_ops($channel);
|
|
}
|
|
}
|
|
}
|
|
|
|
1;
|