mirror of
				https://github.com/pragma-/pbot.git
				synced 2025-11-04 00:27:23 +01:00 
			
		
		
		
	Refactor BanTracker into BanList; move stuff out off ChanOps
This commit is contained in:
		
							parent
							
								
									8b6b969b97
								
							
						
					
					
						commit
						ea19abad4f
					
				@ -171,7 +171,7 @@ sub check_flood {
 | 
			
		||||
    my $account;
 | 
			
		||||
 | 
			
		||||
    if ($mode == $self->{pbot}->{messagehistory}->{MSG_JOIN} and exists $self->{changinghost}->{$nick}) {
 | 
			
		||||
        $self->{pbot}->{logger}->log("Finalizing changinghost for $nick!\n");
 | 
			
		||||
        $self->{pbot}->{logger}->log("Finalizing host change for $nick.\n");
 | 
			
		||||
        $account = delete $self->{changinghost}->{$nick};
 | 
			
		||||
 | 
			
		||||
        my $id = $self->{pbot}->{messagehistory}->{database}->get_message_account_id($mask);
 | 
			
		||||
@ -373,8 +373,15 @@ sub check_flood {
 | 
			
		||||
                            my $banmask  = $self->address_to_mask($host);
 | 
			
		||||
 | 
			
		||||
                            if ($self->{pbot}->{channels}->is_active_op("${channel}-floodbans")) {
 | 
			
		||||
                                $self->{pbot}->{chanops}
 | 
			
		||||
                                  ->ban_user_timed($self->{pbot}->{registry}->get_value('irc', 'botnick'), 'join flooding', "*!$user\@$banmask\$##stop_join_flood", $chan . '-floodbans', $timeout);
 | 
			
		||||
                                $self->{pbot}->{banlist}->ban_user_timed(
 | 
			
		||||
                                    $chan . '-floodbans',
 | 
			
		||||
                                    'b',
 | 
			
		||||
                                    "*!$user\@$banmask\$##stop_join_flood",
 | 
			
		||||
                                    $timeout,
 | 
			
		||||
                                    $self->{pbot}->{registry}->get_value('irc', 'botnick'),
 | 
			
		||||
                                    'join flooding',
 | 
			
		||||
                                );
 | 
			
		||||
 | 
			
		||||
                                $self->{pbot}->{logger}->log("$nick!$user\@$banmask banned for $duration due to join flooding (offense #" . $chan_data->{offenses} . ").\n");
 | 
			
		||||
                                $self->{pbot}->{conn}->privmsg(
 | 
			
		||||
                                    $nick,
 | 
			
		||||
@ -403,8 +410,15 @@ sub check_flood {
 | 
			
		||||
                        if ($self->{pbot}->{registry}->get_value('antiflood', 'enforce')) {
 | 
			
		||||
                            my $length = $self->{pbot}->{registry}->get_array_value('antiflood', 'chat_flood_punishment', $chan_data->{offenses} - 1);
 | 
			
		||||
 | 
			
		||||
                            $self->{pbot}->{chanops}
 | 
			
		||||
                              ->ban_user_timed($self->{pbot}->{registry}->get_value('irc', 'botnick'), 'chat flooding', "*!$user\@" . $self->address_to_mask($host), $chan, $length);
 | 
			
		||||
                            $self->{pbot}->{banlist}->ban_user_timed(
 | 
			
		||||
                                $chan,
 | 
			
		||||
                                'b',
 | 
			
		||||
                                "*!$user\@" . $self->address_to_mask($host),
 | 
			
		||||
                                $length,
 | 
			
		||||
                                $self->{pbot}->{registry}->get_value('irc', 'botnick'),
 | 
			
		||||
                                'chat flooding',
 | 
			
		||||
                            );
 | 
			
		||||
 | 
			
		||||
                            $length = duration($length);
 | 
			
		||||
                            $self->{pbot}->{logger}->log("$nick $chan flood offense " . $chan_data->{offenses} . " earned $length ban\n");
 | 
			
		||||
                            $self->{pbot}->{conn}->privmsg(
 | 
			
		||||
@ -441,8 +455,16 @@ sub check_flood {
 | 
			
		||||
 | 
			
		||||
                    if ($self->{pbot}->{registry}->get_value('antiflood', 'enforce')) {
 | 
			
		||||
                        my $length = $self->{pbot}->{registry}->get_array_value('antiflood', 'nick_flood_punishment', $self->{nickflood}->{$ancestor}->{offenses} - 1);
 | 
			
		||||
                        $self->{pbot}->{chanops}
 | 
			
		||||
                          ->ban_user_timed($self->{pbot}->{registry}->get_value('irc', 'botnick'), 'nick flooding', "*!$user\@" . $self->address_to_mask($host), $chan, $length);
 | 
			
		||||
 | 
			
		||||
                        $self->{pbot}->{banlist}->ban_user_timed(
 | 
			
		||||
                            $chan,
 | 
			
		||||
                            'b',
 | 
			
		||||
                            "*!$user\@" . $self->address_to_mask($host),
 | 
			
		||||
                            $length,
 | 
			
		||||
                            $self->{pbot}->{registry}->get_value('irc', 'botnick'),
 | 
			
		||||
                            'nick flooding',
 | 
			
		||||
                        );
 | 
			
		||||
 | 
			
		||||
                        $length = duration($length);
 | 
			
		||||
                        $self->{pbot}->{logger}->log("$nick nickchange flood offense " . $self->{nickflood}->{$ancestor}->{offenses} . " earned $length ban\n");
 | 
			
		||||
                        $self->{pbot}->{conn}->privmsg($nick, "You have been temporarily banned due to nick-change flooding.  You will be unbanned in $length.");
 | 
			
		||||
@ -481,14 +503,24 @@ sub check_flood {
 | 
			
		||||
 | 
			
		||||
                                my $offenses   = $chan_data->{enter_abuses} - $enter_abuse_max_offenses + 1 + $other_offenses;
 | 
			
		||||
                                my $ban_length = $self->{pbot}->{registry}->get_array_value('antiflood', 'enter_abuse_punishment', $offenses - 1);
 | 
			
		||||
                                $self->{pbot}->{chanops}
 | 
			
		||||
                                  ->ban_user_timed($self->{pbot}->{registry}->get_value('irc', 'botnick'), 'enter abuse', "*!$user\@" . $self->address_to_mask($host), $chan, $ban_length);
 | 
			
		||||
 | 
			
		||||
                                $self->{pbot}->{banlist}->ban_user_timed(
 | 
			
		||||
                                    $chan,
 | 
			
		||||
                                    'b',
 | 
			
		||||
                                    "*!$user\@" . $self->address_to_mask($host),
 | 
			
		||||
                                    $ban_length,
 | 
			
		||||
                                    $self->{pbot}->{registry}->get_value('irc', 'botnick'),
 | 
			
		||||
                                    'enter abuse',
 | 
			
		||||
                                );
 | 
			
		||||
 | 
			
		||||
                                $ban_length = duration($ban_length);
 | 
			
		||||
                                $self->{pbot}->{logger}->log("$nick $chan enter abuse offense " . $chan_data->{enter_abuses} . " earned $ban_length ban\n");
 | 
			
		||||
 | 
			
		||||
                                $self->{pbot}->{conn}->privmsg(
 | 
			
		||||
                                    $nick,
 | 
			
		||||
                                    "You have been muted due to abusing the enter key.  Please do not split your sentences over multiple messages.  You will be allowed to speak again in approximately $ban_length."
 | 
			
		||||
                                );
 | 
			
		||||
 | 
			
		||||
                                $chan_data->{last_offense} = gettimeofday;
 | 
			
		||||
                                $self->{pbot}->{messagehistory}->{database}->update_channel_data($account, $chan, $chan_data);
 | 
			
		||||
                                next;
 | 
			
		||||
@ -548,7 +580,7 @@ sub unbanme {
 | 
			
		||||
 | 
			
		||||
        foreach my $channel (@channels) {
 | 
			
		||||
            next if exists $unbanned->{$channel} and exists $unbanned->{$channel}->{$mask};
 | 
			
		||||
            next if not $self->{pbot}->{chanops}->{unban_timeout}->exists($channel . '-floodbans', $mask);
 | 
			
		||||
            next if not $self->{pbot}->{banlist}->{banlist}->exists($channel . '-floodbans', $mask);
 | 
			
		||||
 | 
			
		||||
            my $message_account   = $self->{pbot}->{messagehistory}->{database}->get_message_account($anick, $auser, $ahost);
 | 
			
		||||
            my @nickserv_accounts = $self->{pbot}->{messagehistory}->{database}->get_nickserv_accounts($message_account);
 | 
			
		||||
@ -556,7 +588,7 @@ sub unbanme {
 | 
			
		||||
            push @nickserv_accounts, undef;
 | 
			
		||||
 | 
			
		||||
            foreach my $nickserv_account (@nickserv_accounts) {
 | 
			
		||||
                my $baninfos = $self->{pbot}->{bantracker}->get_baninfo("$anick!$auser\@$ahost", $channel, $nickserv_account);
 | 
			
		||||
                my $baninfos = $self->{pbot}->{banlist}->get_baninfo($channel, "$anick!$auser\@$ahost", $nickserv_account);
 | 
			
		||||
 | 
			
		||||
                if (defined $baninfos) {
 | 
			
		||||
                    foreach my $baninfo (@$baninfos) {
 | 
			
		||||
@ -598,7 +630,7 @@ sub unbanme {
 | 
			
		||||
            foreach my $mask (keys %{$unbanned->{$channel}}) {
 | 
			
		||||
                if ($self->{pbot}->{channels}->is_active_op("${channel}-floodbans")) {
 | 
			
		||||
                    if ($unbanned->{$channel}->{$mask} <= 2) {
 | 
			
		||||
                        $self->{pbot}->{chanops}->unban_user($mask, $channel . '-floodbans');
 | 
			
		||||
                        $self->{pbot}->{banlist}->unban_user($channel . '-floodbans', 'b', $mask);
 | 
			
		||||
                        $channels .= "$sep$channel";
 | 
			
		||||
                        $sep = ", ";
 | 
			
		||||
                    }
 | 
			
		||||
@ -614,7 +646,7 @@ sub unbanme {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $self->{pbot}->{chanops}->check_unban_queue();
 | 
			
		||||
        $self->{pbot}->{banlist}->flush_unban_queue();
 | 
			
		||||
 | 
			
		||||
        $channels          =~ s/(.*), /$1 and /;
 | 
			
		||||
        $channels_warning  =~ s/(.*), /$1 and /;
 | 
			
		||||
@ -624,16 +656,16 @@ sub unbanme {
 | 
			
		||||
 | 
			
		||||
        if (length $channels_warning) {
 | 
			
		||||
            $warning =
 | 
			
		||||
              " You may use `unbanme` one more time today for $channels_warning; please ensure that your client or connection issues are resolved before using your final `unbanme` of the day.";
 | 
			
		||||
              " You may use `unbanme` one more time today for $channels_warning; please ensure that your client or connection issues are resolved.";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (length $channels_disabled) {
 | 
			
		||||
            $warning .=
 | 
			
		||||
              " You may not use `unbanme` again for several hours for $channels_disabled; ensure that your client or connection issues are resolved, otherwise leave the channel until they are or you will be temporarily banned for several hours if you join-flood again during this period.";
 | 
			
		||||
              " You may not use `unbanme` again for several hours for $channels_disabled.";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if   (length $channels) { return "/msg $nick You have been unbanned from $channels.$warning"; }
 | 
			
		||||
        else                    { return "/msg $nick You were not unbanned at this time.$warning"; }
 | 
			
		||||
        else                    { return "/msg $nick $warning"; }
 | 
			
		||||
    } else {
 | 
			
		||||
        return "/msg $nick There is no join-flooding ban set for you.";
 | 
			
		||||
    }
 | 
			
		||||
@ -783,7 +815,7 @@ sub check_bans {
 | 
			
		||||
 | 
			
		||||
            $self->{pbot}->{logger}->log("anti-flood: [check-bans] checking for bans in $channel on $alias using nickserv " . (defined $nickserv ? $nickserv : "[undefined]") . "\n")
 | 
			
		||||
              if $debug_checkban >= 2;
 | 
			
		||||
            my $baninfos = $self->{pbot}->{bantracker}->get_baninfo($alias, $channel, $nickserv);
 | 
			
		||||
            my $baninfos = $self->{pbot}->{banlist}->get_baninfo($channel, $alias, $nickserv);
 | 
			
		||||
 | 
			
		||||
            if (defined $baninfos) {
 | 
			
		||||
                foreach my $baninfo (@$baninfos) {
 | 
			
		||||
@ -846,7 +878,7 @@ sub check_bans {
 | 
			
		||||
            if ($host =~ m{^([^/]+)/.+} and $1 ne 'gateway' and $1 ne 'nat') { $banmask = "*!*\@$host"; }
 | 
			
		||||
            elsif ( $current_nickserv_account
 | 
			
		||||
                and $baninfo->{banmask} !~ m/^\$a:/i
 | 
			
		||||
                and not exists $self->{pbot}->{bantracker}->{banlist}->{$baninfo->{channel}}->{'+b'}->{"\$a:$current_nickserv_account"})
 | 
			
		||||
                and not $self->{pbot}->{banlist}->{banlist}->exists($baninfo->{channel}, "\$a:$current_nickserv_account"))
 | 
			
		||||
            {
 | 
			
		||||
                $banmask = "\$a:$current_nickserv_account";
 | 
			
		||||
            } else {
 | 
			
		||||
@ -854,7 +886,6 @@ sub check_bans {
 | 
			
		||||
                elsif ($host =~ m{^nat/([^/]+)/})              { $banmask = "*!$user\@nat/$1/*"; }
 | 
			
		||||
                else {
 | 
			
		||||
                    $banmask = "*!*\@$host";
 | 
			
		||||
 | 
			
		||||
                    #$banmask = "*!$user@" . $self->address_to_mask($host);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@ -886,7 +917,13 @@ sub check_bans {
 | 
			
		||||
                    $owner =~ s/!.*$//;
 | 
			
		||||
                    $self->{pbot}->{chanops}->add_op_command($baninfo->{channel}, "kick $baninfo->{channel} $bannick Evaded $baninfo->{banmask} set by $owner");
 | 
			
		||||
                }
 | 
			
		||||
                $self->{pbot}->{chanops}->ban_user_timed($self->{pbot}->{registry}->get_value('irc', 'botnick'), 'ban evasion', $banmask, $baninfo->{channel}, 60 * 60 * 24 * 14);
 | 
			
		||||
                $self->{pbot}->{banlist}->ban_user_timed(
 | 
			
		||||
                    $banmask, $baninfo->{channel},
 | 
			
		||||
                    'b',
 | 
			
		||||
                    60 * 60 * 24 * 14,
 | 
			
		||||
                    $self->{pbot}->{registry}->get_value('irc', 'botnick'),
 | 
			
		||||
                    'ban evasion',
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
            my $channel_data = $self->{pbot}->{messagehistory}->{database}->get_channel_data($message_account, $channel, 'validated');
 | 
			
		||||
            if ($channel_data->{validated} & $self->{NICKSERV_VALIDATED}) {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										770
									
								
								PBot/BanList.pm
									
									
									
									
									
								
							
							
						
						
									
										770
									
								
								PBot/BanList.pm
									
									
									
									
									
								
							@ -1,16 +1,15 @@
 | 
			
		||||
# File: BanTracker.pm
 | 
			
		||||
# File: BanList.pm
 | 
			
		||||
# Author: pragma_
 | 
			
		||||
#
 | 
			
		||||
# Purpose: Populates and maintains channel banlists by checking mode +b on
 | 
			
		||||
# joining channels and by tracking modes +b and -b in channels.
 | 
			
		||||
#
 | 
			
		||||
# Does NOT do banning or unbanning.
 | 
			
		||||
# Purpose: Populates and maintains channel banlists by checking mode +b/+q on
 | 
			
		||||
# joining channels and by tracking modes +b/+q and -b/-q in channels. Keeps
 | 
			
		||||
# track of remaining duration for timed bans/quiets. Handles ban/unban queue.
 | 
			
		||||
 | 
			
		||||
# This Source Code Form is subject to the terms of the Mozilla Public
 | 
			
		||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
 | 
			
		||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
 | 
			
		||||
 | 
			
		||||
package PBot::BanTracker;
 | 
			
		||||
package PBot::BanList;
 | 
			
		||||
 | 
			
		||||
use parent 'PBot::Class';
 | 
			
		||||
 | 
			
		||||
@ -20,36 +19,140 @@ use feature 'unicode_strings';
 | 
			
		||||
use Time::HiRes qw/gettimeofday/;
 | 
			
		||||
use Time::Duration;
 | 
			
		||||
use Data::Dumper;
 | 
			
		||||
use POSIX qw/strftime/;
 | 
			
		||||
 | 
			
		||||
$Data::Dumper::Sortkeys = 1;
 | 
			
		||||
 | 
			
		||||
sub initialize {
 | 
			
		||||
    my ($self, %conf) = @_;
 | 
			
		||||
    $self->{pbot}->{registry}->add_default('text', 'bantracker', 'chanserv_ban_timeout', '604800');
 | 
			
		||||
    $self->{pbot}->{registry}->add_default('text', 'bantracker', 'mute_timeout',         '604800');
 | 
			
		||||
    $self->{pbot}->{registry}->add_default('text', 'bantracker', 'debug',                '0');
 | 
			
		||||
 | 
			
		||||
    $self->{pbot}->{commands}->register(sub { $self->dumpbans(@_) }, "dumpbans", 1);
 | 
			
		||||
    $self->{pbot}->{registry}->add_default('text', 'banlist', 'chanserv_ban_timeout', '604800');
 | 
			
		||||
    $self->{pbot}->{registry}->add_default('text', 'banlist', 'mute_timeout',         '604800');
 | 
			
		||||
    $self->{pbot}->{registry}->add_default('text', 'banlist', 'debug',                '0');
 | 
			
		||||
 | 
			
		||||
    $self->{pbot}->{event_dispatcher}->register_handler('irc.endofnames', sub { $self->get_banlist(@_) });
 | 
			
		||||
    $self->{pbot}->{event_dispatcher}->register_handler('irc.banlist',    sub { $self->on_banlist_entry(@_) });
 | 
			
		||||
    $self->{pbot}->{event_dispatcher}->register_handler('irc.quietlist',  sub { $self->on_quietlist_entry(@_) });
 | 
			
		||||
    $self->{pbot}->{commands}->register(sub { $self->banlist_cmd(@_) },   "banlist",   0);
 | 
			
		||||
    $self->{pbot}->{commands}->register(sub { $self->checkban_cmd(@_) },  "checkban",  0);
 | 
			
		||||
    $self->{pbot}->{commands}->register(sub { $self->checkmute_cmd(@_) }, "checkmute", 0);
 | 
			
		||||
 | 
			
		||||
    $self->{banlist} = {};
 | 
			
		||||
    $self->{pbot}->{event_dispatcher}->register_handler('irc.endofnames',     sub { $self->get_banlist(@_) });
 | 
			
		||||
    $self->{pbot}->{event_dispatcher}->register_handler('irc.banlist',        sub { $self->on_banlist_entry(@_) });
 | 
			
		||||
    $self->{pbot}->{event_dispatcher}->register_handler('irc.quietlist',      sub { $self->on_quietlist_entry(@_) });
 | 
			
		||||
    $self->{pbot}->{event_dispatcher}->register_handler('irc.endofbanlist',   sub { $self->compare_banlist(@_) });
 | 
			
		||||
    $self->{pbot}->{event_dispatcher}->register_handler('irc.endofquietlist', sub { $self->compare_quietlist(@_) });
 | 
			
		||||
 | 
			
		||||
    $self->{banlist} = PBot::DualIndexHashObject->new(
 | 
			
		||||
        pbot     => $self->{pbot},
 | 
			
		||||
        name     => 'Ban List',
 | 
			
		||||
        filename => $self->{pbot}->{registry}->get_value('general', 'data_dir') . '/banlist'
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    $self->{quietlist} = PBot::DualIndexHashObject->new(
 | 
			
		||||
        pbot     => $self->{pbot},
 | 
			
		||||
        name     => 'Quiet List',
 | 
			
		||||
        filename => $self->{pbot}->{registry}->get_value('general', 'data_dir') . '/quietlist'
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    $self->{banlist}->load;
 | 
			
		||||
    $self->{quietlist}->load;
 | 
			
		||||
 | 
			
		||||
    $self->enqueue_timeouts($self->{banlist},   'b');
 | 
			
		||||
    $self->enqueue_timeouts($self->{quietlist}, 'q');
 | 
			
		||||
 | 
			
		||||
    $self->{ban_queue}   = {};
 | 
			
		||||
    $self->{unban_queue} = {};
 | 
			
		||||
 | 
			
		||||
    $self->{pbot}->{timer}->register(sub { $self->flush_unban_queue }, 30, 'Unban Queue');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub dumpbans {
 | 
			
		||||
sub banlist_cmd {
 | 
			
		||||
    my ($self, $from, $nick, $user, $host, $arguments) = @_;
 | 
			
		||||
    my $bans = Dumper($self->{banlist});
 | 
			
		||||
    return $bans;
 | 
			
		||||
 | 
			
		||||
    if (not length $arguments) {
 | 
			
		||||
        return "Usage: banlist <channel>";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    my $result = "Ban list for $arguments:\n";
 | 
			
		||||
 | 
			
		||||
    if ($self->{banlist}->exists($arguments)) {
 | 
			
		||||
        my $count = $self->{banlist}->get_keys($arguments);
 | 
			
		||||
        $result .= "$count bans:\n";
 | 
			
		||||
        foreach my $mask ($self->{banlist}->get_keys($arguments)) {
 | 
			
		||||
            my $data = $self->{banlist}->get_data($arguments, $mask);
 | 
			
		||||
            $result .= "  $mask banned ";
 | 
			
		||||
 | 
			
		||||
            if (defined $data->{timestamp}) {
 | 
			
		||||
                my $date = strftime "%a %b %e %H:%M:%S %Y %Z", localtime $data->{timestamp};
 | 
			
		||||
                my $ago = concise ago (time - $data->{timestamp});
 | 
			
		||||
                $result .= "on $date ($ago) ";
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $result .= "by $data->{owner} "   if defined $data->{owner};
 | 
			
		||||
            $result .= "for $data->{reason} " if defined $data->{reason};
 | 
			
		||||
            if (defined $data->{timeout} and $data->{timeout} > 0) {
 | 
			
		||||
                my $duration = concise duration($data->{timeout} - gettimeofday);
 | 
			
		||||
                $result .= "($duration remaining)";
 | 
			
		||||
            }
 | 
			
		||||
            $result .= ";\n";
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        $result .= "bans: none;\n";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ($self->{quietlist}->exists($arguments)) {
 | 
			
		||||
        my $count = $self->{quietlist}->get_keys($arguments);
 | 
			
		||||
        $result .= "$count mutes:\n";
 | 
			
		||||
        foreach my $mask ($self->{quietlist}->get_keys($arguments)) {
 | 
			
		||||
            my $data = $self->{quietlist}->get_data($arguments, $mask);
 | 
			
		||||
            $result .= "  $mask muted ";
 | 
			
		||||
 | 
			
		||||
            if (defined $data->{timestamp}) {
 | 
			
		||||
                my $date = strftime "%a %b %e %H:%M:%S %Y %Z", localtime $data->{timestamp};
 | 
			
		||||
                my $ago = concise ago (time - $data->{timestamp});
 | 
			
		||||
                $result .= "on $date ($ago ago) ";
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $result .= "by $data->{owner} "   if defined $data->{owner};
 | 
			
		||||
            $result .= "for $data->{reason} " if defined $data->{reason};
 | 
			
		||||
            if (defined $data->{timeout} and $data->{timeout} > 0) {
 | 
			
		||||
                my $duration = concise duration($data->{timeout} - gettimeofday);
 | 
			
		||||
                $result .= "($duration remaining)";
 | 
			
		||||
            }
 | 
			
		||||
            $result .= ";\n";
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        $result .= "quiets: none;\n";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return $result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub checkban_cmd {
 | 
			
		||||
    my ($self, $from, $nick, $user, $host, $arguments, $stuff) = @_;
 | 
			
		||||
    my ($target, $channel) = $self->{pbot}->{interpreter}->split_args($stuff->{arglist}, 2);
 | 
			
		||||
 | 
			
		||||
    return "Usage: checkban <mask> [channel]" if not defined $target;
 | 
			
		||||
    $channel = $from if not defined $channel;
 | 
			
		||||
 | 
			
		||||
    return "Please specify a channel." if $channel !~ /^#/;
 | 
			
		||||
    return $self->checkban($channel, 'b', $target);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub checkmute_cmd {
 | 
			
		||||
    my ($self, $from, $nick, $user, $host, $arguments, $stuff) = @_;
 | 
			
		||||
    my ($target, $channel) = $self->{pbot}->{interpreter}->split_args($stuff->{arglist}, 2);
 | 
			
		||||
 | 
			
		||||
    return "Usage: checkmute <mask> [channel]" if not defined $target;
 | 
			
		||||
    $channel = $from if not defined $channel;
 | 
			
		||||
 | 
			
		||||
    return "Please specify a channel." if $channel !~ /^#/;
 | 
			
		||||
    return $self->checkban($channel, 'q', $target);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub get_banlist {
 | 
			
		||||
    my ($self, $event_type, $event) = @_;
 | 
			
		||||
    my $channel = lc $event->{event}->{args}[1];
 | 
			
		||||
    return 0 if not $self->{pbot}->{chanops}->can_gain_ops($channel);
 | 
			
		||||
    delete $self->{banlist}->{$channel};
 | 
			
		||||
    $self->{pbot}->{logger}->log("Retrieving banlist for $channel.\n");
 | 
			
		||||
    delete $self->{temp_banlist};
 | 
			
		||||
    $event->{conn}->sl("mode $channel +bq");
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
@ -60,33 +163,11 @@ sub on_banlist_entry {
 | 
			
		||||
    my $channel   = lc $event->{event}->{args}[1];
 | 
			
		||||
    my $target    = lc $event->{event}->{args}[2];
 | 
			
		||||
    my $source    = lc $event->{event}->{args}[3];
 | 
			
		||||
    my $timestamp = $event->{event}->{args}[4];
 | 
			
		||||
    my $timestamp =    $event->{event}->{args}[4];
 | 
			
		||||
 | 
			
		||||
    my $ago = ago(gettimeofday - $timestamp);
 | 
			
		||||
 | 
			
		||||
    $self->{pbot}->{logger}->log("ban-tracker: [banlist entry] $channel: $target banned by $source $ago.\n");
 | 
			
		||||
    $self->{banlist}->{$channel}->{'+b'}->{$target} = [$source, $timestamp];
 | 
			
		||||
 | 
			
		||||
    if ($target =~ m/^\*!\*@/ or $target =~ m/^\*!.*\@gateway\/web/i) {
 | 
			
		||||
        my $timeout = 60 * 60 * 24 * 7;
 | 
			
		||||
 | 
			
		||||
        if ($target =~ m/\// and $target !~ m/\@gateway/) {
 | 
			
		||||
            $timeout = 0;    # permanent bans for cloaks that aren't gateway
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($timeout && $self->{pbot}->{chanops}->can_gain_ops($channel)) {
 | 
			
		||||
            if (not $self->{pbot}->{chanops}->{unban_timeout}->exists($channel, $target)) {
 | 
			
		||||
                $self->{pbot}->{logger}->log("Temp ban for $target in $channel.\n");
 | 
			
		||||
                my $data = {
 | 
			
		||||
                    timeout => gettimeofday + $timeout,
 | 
			
		||||
                    owner   => $source,
 | 
			
		||||
                    reason  => 'Temp ban on *!*@... or *!...@gateway/web'
 | 
			
		||||
                };
 | 
			
		||||
                $self->{pbot}->{chanops}->{unban_timeout}->add($channel, $target, $data);
 | 
			
		||||
                $self->{pbot}->{chanops}->enqueue_unban_timeout($channel, $target, $timeout);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    my $ago = concise ago(gettimeofday - $timestamp);
 | 
			
		||||
    $self->{pbot}->{logger}->log("banlist: [banlist entry] $channel: $target banned by $source $ago.\n");
 | 
			
		||||
    $self->{temp_banlist}->{$channel}->{'+b'}->{$target} = [$source, $timestamp];
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -96,58 +177,310 @@ sub on_quietlist_entry {
 | 
			
		||||
    my $channel   = lc $event->{event}->{args}[1];
 | 
			
		||||
    my $target    = lc $event->{event}->{args}[3];
 | 
			
		||||
    my $source    = lc $event->{event}->{args}[4];
 | 
			
		||||
    my $timestamp = $event->{event}->{args}[5];
 | 
			
		||||
    my $timestamp =    $event->{event}->{args}[5];
 | 
			
		||||
 | 
			
		||||
    my $ago = ago(gettimeofday - $timestamp);
 | 
			
		||||
 | 
			
		||||
    $self->{pbot}->{logger}->log("ban-tracker: [quietlist entry] $channel: $target quieted by $source $ago.\n");
 | 
			
		||||
    $self->{banlist}->{$channel}->{'+q'}->{$target} = [$source, $timestamp];
 | 
			
		||||
    my $ago = concise ago(gettimeofday - $timestamp);
 | 
			
		||||
    $self->{pbot}->{logger}->log("banlist: [quietlist entry] $channel: $target quieted by $source $ago.\n");
 | 
			
		||||
    $self->{temp_banlist}->{$channel}->{'+q'}->{$target} = [$source, $timestamp];
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub compare_banlist {
 | 
			
		||||
    my ($self, $event_type, $event) = @_;
 | 
			
		||||
    my $channel = lc $event->{event}->{args}[1];
 | 
			
		||||
 | 
			
		||||
    $self->{pbot}->{logger}->log("Finalizing ban list for $channel\n");
 | 
			
		||||
 | 
			
		||||
    # first check for saved bans no longer in channel
 | 
			
		||||
    foreach my $mask ($self->{banlist}->get_keys($channel)) {
 | 
			
		||||
        if (not exists $self->{temp_banlist}->{$channel}->{'+b'}->{$mask}) {
 | 
			
		||||
            $self->{pbot}->{logger}->log("BanList: Saved ban +b $mask no longer exists in $channel.\n");
 | 
			
		||||
            # TODO option to restore ban
 | 
			
		||||
            $self->{banlist}->remove($channel, $mask, undef, 1);
 | 
			
		||||
            $self->{pbot}->{timer}->dequeue_event("unban $channel $mask");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    # add channel bans to saved bans
 | 
			
		||||
    foreach my $mask (keys %{$self->{temp_banlist}->{$channel}->{'+b'}}) {
 | 
			
		||||
        my $data = $self->{banlist}->get_data($channel, $mask);
 | 
			
		||||
        $data->{owner}     = $self->{temp_banlist}->{$channel}->{'+b'}->{$mask}->[0];
 | 
			
		||||
        $data->{timestamp} = $self->{temp_banlist}->{$channel}->{'+b'}->{$mask}->[1];
 | 
			
		||||
 | 
			
		||||
        # make some special-case bans temporary
 | 
			
		||||
        if (not defined $data->{timeout} and $self->{pbot}->{chanops}->can_gain_ops($channel)) {
 | 
			
		||||
            if ($mask =~ m/^\*!\*@/ or $mask =~ m/^\*!.*\@gateway\/web/i) {
 | 
			
		||||
                my $timeout = 60 * 60 * 24 * 7;
 | 
			
		||||
 | 
			
		||||
                # permanent bans for cloaks that aren't gateway
 | 
			
		||||
                $timeout = 0 if $mask =~ m/\// and $mask !~ m/\@gateway/;
 | 
			
		||||
 | 
			
		||||
                if ($timeout) {
 | 
			
		||||
                    $self->{pbot}->{logger}->log("Temp ban for $mask in $channel.\n");
 | 
			
		||||
                    $data->{timeout} = gettimeofday + $timeout;
 | 
			
		||||
                    $self->{pbot}->{chanops}->enqueue_unban($channel, 'b', $mask, $timeout);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $self->{banlist}->add($channel, $mask, $data, 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $self->{banlist}->save;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub compare_quietlist {
 | 
			
		||||
    my ($self, $event_type, $event) = @_;
 | 
			
		||||
    my $channel = lc $event->{event}->{args}[1];
 | 
			
		||||
 | 
			
		||||
    $self->{pbot}->{logger}->log("Finalizing quiet list for $channel\n");
 | 
			
		||||
 | 
			
		||||
    # first check for saved quiets no longer in channel
 | 
			
		||||
    foreach my $mask ($self->{quietlist}->get_keys($channel)) {
 | 
			
		||||
        if (not exists $self->{temp_banlist}->{$channel}->{'+q'}->{$mask}) {
 | 
			
		||||
            $self->{pbot}->{logger}->log("BanList: Saved quiet +q $mask no longer exists in $channel.\n");
 | 
			
		||||
            # TODO option to restore quiet
 | 
			
		||||
            $self->{quietlist}->remove($channel, $mask, undef, 1);
 | 
			
		||||
            $self->{pbot}->{timer}->dequeue_event("unmute $channel $mask");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    # add channel bans to saved bans
 | 
			
		||||
    foreach my $mask (keys %{$self->{temp_banlist}->{$channel}->{'+q'}}) {
 | 
			
		||||
        my $data = $self->{quietlist}->get_data($channel, $mask);
 | 
			
		||||
        $data->{owner}     = $self->{temp_banlist}->{$channel}->{'+q'}->{$mask}->[0];
 | 
			
		||||
        $data->{timestamp} = $self->{temp_banlist}->{$channel}->{'+q'}->{$mask}->[1];
 | 
			
		||||
        $self->{quietlist}->add($channel, $mask, $data, 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $self->{quietlist}->save;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub track_mode {
 | 
			
		||||
    my $self = shift;
 | 
			
		||||
    my ($source, $channel, $mode, $mask) = @_;
 | 
			
		||||
 | 
			
		||||
    my ($nick) = $source =~ /(^[^!]+)/;
 | 
			
		||||
    $channel = lc $channel;
 | 
			
		||||
    $mask    = lc $mask;
 | 
			
		||||
 | 
			
		||||
    if ($mode eq "+b" or $mode eq "+q") {
 | 
			
		||||
        $self->{pbot}->{logger}->log("banlist: $mask " . ($mode eq '+b' ? 'banned' : 'quieted') . " by $source in $channel.\n");
 | 
			
		||||
 | 
			
		||||
        my $data = {
 | 
			
		||||
            owner => $source,
 | 
			
		||||
            timestamp => gettimeofday,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        if ($mode eq "+b") {
 | 
			
		||||
            $self->{banlist}->add($channel, $mask, $data);
 | 
			
		||||
        } elsif ($mode eq "+q") {
 | 
			
		||||
            $self->{quietlist}->add($channel, $mask, $data);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $self->{pbot}->{antiflood}->devalidate_accounts($mask, $channel);
 | 
			
		||||
    } elsif ($mode eq "-b" or $mode eq "-q") {
 | 
			
		||||
        $self->{pbot}->{logger}->log("banlist: $mask " . ($mode eq '-b' ? 'unbanned' : 'unquieted') . " by $source in $channel.\n");
 | 
			
		||||
 | 
			
		||||
        if ($mode eq "-b") {
 | 
			
		||||
            $self->{banlist}->remove($channel, $mask);
 | 
			
		||||
            $self->{pbot}->{timer}->dequeue_event("unban $channel $mask");
 | 
			
		||||
 | 
			
		||||
            # freenode strips channel forwards from unban result if no ban exists with a channel forward
 | 
			
		||||
            $self->{banlist}->remove($channel, "$mask\$##stop_join_flood");
 | 
			
		||||
            $self->{pbot}->{timer}->dequeue_event(lc "unban $channel $mask\$##stop_join_flood");
 | 
			
		||||
        } elsif ($mode eq "-q") {
 | 
			
		||||
            $self->{quietlist}->remove($channel, $mask);
 | 
			
		||||
            $self->{pbot}->{timer}->dequeue_event("unmute $channel $mask");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return if not $self->{pbot}->{chanops}->can_gain_ops($channel);
 | 
			
		||||
 | 
			
		||||
    if ($mode eq "+b") {
 | 
			
		||||
        if ($nick eq "ChanServ" or $mask =~ m/##fix_your_connection$/i) {
 | 
			
		||||
            if ($self->{banlist}->exists($channel, $mask)) {
 | 
			
		||||
                $self->{banlist}->set($channel, $mask, 'timeout', gettimeofday + $self->{pbot}->{registry}->get_value('banlist', 'chanserv_ban_timeout'));
 | 
			
		||||
                $self->{pbot}->{timer}->update_interval("unban $channel $mask", $self->{pbot}->{registry}->get_value('banlist', 'chanserv_ban_timeout'));
 | 
			
		||||
            } else {
 | 
			
		||||
                my $data = {
 | 
			
		||||
                    reason    => 'Temp ban for banned-by-ChanServ or mask is *!*@*##fix_your_connection',
 | 
			
		||||
                    owner     => $self->{pbot}->{registry}->get_value('irc', 'botnick'),
 | 
			
		||||
                    timeout   => gettimeofday + $self->{pbot}->{registry}->get_value('banlist', 'chanserv_ban_timeout'),
 | 
			
		||||
                    timestamp => gettimeofday,
 | 
			
		||||
                };
 | 
			
		||||
                $self->{banlist}->add($channel, $mask, $data);
 | 
			
		||||
                $self->enqueue_unban($channel, 'b', $mask, $self->{pbot}->{registry}->get_value('banlist', 'chanserv_ban_timeout'));
 | 
			
		||||
            }
 | 
			
		||||
        } elsif ($mask =~ m/^\*!\*@/ or $mask =~ m/^\*!.*\@gateway\/web/i) {
 | 
			
		||||
            my $timeout = 60 * 60 * 24 * 7;
 | 
			
		||||
 | 
			
		||||
            if ($mask =~ m/\// and $mask !~ m/\@gateway/) {
 | 
			
		||||
                $timeout = 0;    # permanent bans for cloaks that aren't gateway
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if ($timeout) {
 | 
			
		||||
                if (not $self->{banlist}->exists($channel, $mask)) {
 | 
			
		||||
                    $self->{pbot}->{logger}->log("Temp ban for $mask in $channel.\n");
 | 
			
		||||
                    my $data = {
 | 
			
		||||
                        reason    => 'Temp ban for *!*@... banmask',
 | 
			
		||||
                        timeout   => gettimeofday + $timeout,
 | 
			
		||||
                        owner     => $self->{pbot}->{registry}->get_value('irc', 'botnick'),
 | 
			
		||||
                        timestamp => gettimeofday,
 | 
			
		||||
                    };
 | 
			
		||||
                    $self->{banlist}->add($channel, $mask, $data);
 | 
			
		||||
                    $self->enqueue_unban($channel, 'b', $mask, $timeout);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    } elsif ($mode eq "+q") {
 | 
			
		||||
        if (lc $nick ne lc $self->{pbot}->{registry}->get_value('irc', 'botnick')) {
 | 
			
		||||
            $self->{pbot}->{logger}->log("WEIRD MUTE THING $nick...\n");
 | 
			
		||||
            if ($self->{quietlist}->exists($channel, $mask)) {
 | 
			
		||||
                $self->{quietlist}->set($channel, $mask, 'timeout', gettimeofday + $self->{pbot}->{registry}->get_value('banlist', 'chanserv_ban_timeout'));
 | 
			
		||||
                $self->{pbot}->{timer}->update_interval("unmute $channel $mask", $self->{pbot}->{registry}->get_value('banlist', 'chanserv_ban_timeout'));
 | 
			
		||||
            } else {
 | 
			
		||||
                my $data = {
 | 
			
		||||
                    reason    => 'Temp mute',
 | 
			
		||||
                    owner     => $self->{pbot}->{registry}->get_value('irc', 'botnick'),
 | 
			
		||||
                    timeout   => gettimeofday + $self->{pbot}->{registry}->get_value('banlist', 'mute_timeout'),
 | 
			
		||||
                    timestamp => gettimeofday,
 | 
			
		||||
                };
 | 
			
		||||
                $self->{quietlist}->add($channel, $mask, $data);
 | 
			
		||||
                $self->enqueue_unban($channel, 'q', $mask, $self->{pbot}->{registry}->get_value('banlist', 'mute_timeout'));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub ban_user {
 | 
			
		||||
    my ($self, $channel, $mode, $mask, $immediately) = @_;
 | 
			
		||||
    $mode ||= 'b';
 | 
			
		||||
    $self->{pbot}->{logger}->log("Banning $channel +$mode $mask\n");
 | 
			
		||||
    $self->add_to_ban_queue($channel, $mode, $mask);
 | 
			
		||||
    if (not defined $immediately or $immediately != 0) {
 | 
			
		||||
        $self->flush_ban_queue;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub unban_user {
 | 
			
		||||
    my ($self, $channel, $mode, $mask, $immediately) = @_;
 | 
			
		||||
    $mask    = lc $mask;
 | 
			
		||||
    $channel = lc $channel;
 | 
			
		||||
    $mode ||= 'b';
 | 
			
		||||
    $self->{pbot}->{logger}->log("Unbanning $channel -$mode $mask\n");
 | 
			
		||||
    $self->unmode_user($channel, $mode, $mask, $immediately);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub unmode_user {
 | 
			
		||||
    my ($self, $channel, $mode, $mask, $immediately) = @_;
 | 
			
		||||
 | 
			
		||||
    $mask    = lc $mask;
 | 
			
		||||
    $channel = lc $channel;
 | 
			
		||||
    $self->{pbot}->{logger}->log("Removing mode $mode from $mask in $channel\n");
 | 
			
		||||
 | 
			
		||||
    my $bans = $self->get_bans($channel, $mask);
 | 
			
		||||
    my %unbanned;
 | 
			
		||||
 | 
			
		||||
    if (not defined $bans) {
 | 
			
		||||
        push @$bans, { banmask => $mask, type => "+$mode" };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    foreach my $ban (@$bans) {
 | 
			
		||||
        next if $ban->{type} ne "+$mode";
 | 
			
		||||
        next if exists $unbanned{$ban->{banmask}};
 | 
			
		||||
        $unbanned{$ban->{banmask}} = 1;
 | 
			
		||||
        $self->add_to_unban_queue($channel, $mode, $ban->{banmask});
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $self->flush_unban_queue if $immediately;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub get_bans {
 | 
			
		||||
    my ($self, $channel, $mask) = @_;
 | 
			
		||||
 | 
			
		||||
    my $masks;
 | 
			
		||||
    my ($message_account, $hostmask);
 | 
			
		||||
 | 
			
		||||
    if ($mask !~ m/[!@]/) {
 | 
			
		||||
        ($message_account, $hostmask) = $self->{pbot}->{messagehistory}->{database}->find_message_account_by_nick($mask);
 | 
			
		||||
        $hostmask = $mask if not defined $message_account;
 | 
			
		||||
    } else {
 | 
			
		||||
        $message_account = $self->{pbot}->{messagehistory}->{database}->get_message_account_id($mask);
 | 
			
		||||
        $hostmask = $mask;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (defined $message_account) {
 | 
			
		||||
        my $nickserv = $self->{pbot}->{messagehistory}->{database}->get_current_nickserv_account($message_account);
 | 
			
		||||
        $masks = $self->get_baninfo($channel, $hostmask, $nickserv);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    my %akas = $self->{pbot}->{messagehistory}->{database}->get_also_known_as($hostmask);
 | 
			
		||||
 | 
			
		||||
    foreach my $aka (keys %akas) {
 | 
			
		||||
        next if $akas{$aka}->{type} == $self->{pbot}->{messagehistory}->{database}->{alias_type}->{WEAK};
 | 
			
		||||
        next if $akas{$aka}->{nickchange} == 1;
 | 
			
		||||
 | 
			
		||||
        my $nickserv = $self->{pbot}->{messagehistory}->{database}->get_current_nickserv_account($akas{$aka}->{id});
 | 
			
		||||
 | 
			
		||||
        my $b = $self->get_baninfo($channel, $aka, $nickserv);
 | 
			
		||||
        if (defined $b) {
 | 
			
		||||
            push @$masks, @$b;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return $masks;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub get_baninfo {
 | 
			
		||||
    my ($self, $mask, $channel, $account) = @_;
 | 
			
		||||
    my ($bans, $ban_account);
 | 
			
		||||
    my ($self, $channel, $mask, $nickserv) = @_;
 | 
			
		||||
    my ($bans, $ban_nickserv);
 | 
			
		||||
 | 
			
		||||
    $account = undef       if not length $account;
 | 
			
		||||
    $account = lc $account if defined $account;
 | 
			
		||||
    $nickserv = undef        if not length $nickserv;
 | 
			
		||||
    $nickserv = lc $nickserv if defined $nickserv;
 | 
			
		||||
 | 
			
		||||
    if ($self->{pbot}->{registry}->get_value('bantracker', 'debug')) {
 | 
			
		||||
        $self->{pbot}->{logger}->log("[get-baninfo] Getting baninfo for $mask in $channel using account " . (defined $account ? $account : "[undefined]") . "\n");
 | 
			
		||||
    if ($self->{pbot}->{registry}->get_value('banlist', 'debug')) {
 | 
			
		||||
        my $ns = defined $nickserv ? $nickserv : "[undefined]";
 | 
			
		||||
        $self->{pbot}->{logger}->log("[get-baninfo] Getting baninfo for $mask in $channel using nickserv $ns\n");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    my ($nick, $user, $host) = $mask =~ m/([^!]+)!([^@]+)@(.*)/;
 | 
			
		||||
 | 
			
		||||
    foreach my $mode (keys %{$self->{banlist}->{$channel}}) {
 | 
			
		||||
        foreach my $banmask (keys %{$self->{banlist}->{$channel}->{$mode}}) {
 | 
			
		||||
            if   ($banmask =~ m/^\$a:(.*)/) { $ban_account = lc $1; }
 | 
			
		||||
            else                            { $ban_account = ""; }
 | 
			
		||||
    my @lists = (
 | 
			
		||||
        [ 'b', $self->{banlist}   ],
 | 
			
		||||
        [ 'q', $self->{quietlist} ],
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
            my $banmask_key = $banmask;
 | 
			
		||||
            $banmask = quotemeta $banmask;
 | 
			
		||||
            $banmask =~ s/\\\*/.*?/g;
 | 
			
		||||
            $banmask =~ s/\\\?/./g;
 | 
			
		||||
    foreach my $entry (@lists) {
 | 
			
		||||
        my ($mode, $list) = @$entry;
 | 
			
		||||
        foreach my $banmask ($list->get_keys($channel)) {
 | 
			
		||||
            if   ($banmask =~ m/^\$a:(.*)/) { $ban_nickserv = lc $1; }
 | 
			
		||||
            else                            { $ban_nickserv = ""; }
 | 
			
		||||
 | 
			
		||||
            my $banmask_regex = quotemeta $banmask;
 | 
			
		||||
            $banmask_regex =~ s/\\\*/.*?/g;
 | 
			
		||||
            $banmask_regex =~ s/\\\?/./g;
 | 
			
		||||
 | 
			
		||||
            my $banned;
 | 
			
		||||
            $banned = 1 if defined $nickserv and $nickserv eq $ban_nickserv;
 | 
			
		||||
            $banned = 1 if $mask =~ m/^$banmask_regex$/i;
 | 
			
		||||
 | 
			
		||||
            $banned = 1 if defined $account and $account eq $ban_account;
 | 
			
		||||
            $banned = 1 if $mask =~ m/^$banmask$/i;
 | 
			
		||||
 | 
			
		||||
            if ($banmask_key =~ m{\@gateway/web/irccloud.com} and $host =~ m{^gateway/web/irccloud.com}) {
 | 
			
		||||
                my ($bannick, $banuser, $banhost) = $banmask_key =~ m/([^!]+)!([^@]+)@(.*)/;
 | 
			
		||||
 | 
			
		||||
                if (lc $user eq lc $banuser) { $banned = 1; }
 | 
			
		||||
            if ($banmask =~ m{\@gateway/web/irccloud.com} and $host =~ m{^gateway/web/irccloud.com}) {
 | 
			
		||||
                my ($bannick, $banuser, $banhost) = $banmask =~ m/([^!]+)!([^@]+)@(.*)/;
 | 
			
		||||
                $banned = $1 if lc $user eq lc $banuser;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if ($banned) {
 | 
			
		||||
                if (not defined $bans) { $bans = []; }
 | 
			
		||||
 | 
			
		||||
                my $baninfo = {};
 | 
			
		||||
                $baninfo->{banmask} = $banmask_key;
 | 
			
		||||
                $baninfo->{channel} = $channel;
 | 
			
		||||
                $baninfo->{owner}   = $self->{banlist}->{$channel}->{$mode}->{$banmask_key}->[0];
 | 
			
		||||
                $baninfo->{when}    = $self->{banlist}->{$channel}->{$mode}->{$banmask_key}->[1];
 | 
			
		||||
                $baninfo->{type}    = $mode;
 | 
			
		||||
                my $data = $list->get_data($channel, $banmask);
 | 
			
		||||
                my $baninfo = {
 | 
			
		||||
                    mask    => $banmask,
 | 
			
		||||
                    channel => $channel,
 | 
			
		||||
                    owner   => $data->{owner},
 | 
			
		||||
                    when    => $data->{timestamp},
 | 
			
		||||
                    type    => $mode,
 | 
			
		||||
                    reason  => $data->{reason},
 | 
			
		||||
                    timeout => $data->{timeout},
 | 
			
		||||
                };
 | 
			
		||||
                push @$bans, $baninfo;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@ -156,8 +489,237 @@ sub get_baninfo {
 | 
			
		||||
    return $bans;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub nick_to_banmask {
 | 
			
		||||
    my ($self, $mask) = @_;
 | 
			
		||||
 | 
			
		||||
    if ($mask !~ m/[!@\$]/) {
 | 
			
		||||
        my ($message_account, $hostmask) = $self->{pbot}->{messagehistory}->{database}->find_message_account_by_nick($mask);
 | 
			
		||||
        if (defined $hostmask) {
 | 
			
		||||
            my $nickserv = $self->{pbot}->{messagehistory}->{database}->get_current_nickserv_account($message_account);
 | 
			
		||||
            if (defined $nickserv && length $nickserv) { $mask = '$a:' . $nickserv; }
 | 
			
		||||
            else {
 | 
			
		||||
                my ($nick, $user, $host) = $hostmask =~ m/([^!]+)!([^@]+)@(.*)/;
 | 
			
		||||
                $mask = "*!$user\@" . $self->{pbot}->{antiflood}->address_to_mask($host);
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            $mask .= '!*@*';
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return $mask;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub ban_user_timed {
 | 
			
		||||
    my ($self, $channel, $mode, $mask, $length, $owner, $reason, $immediately) = @_;
 | 
			
		||||
 | 
			
		||||
    $channel = lc $channel;
 | 
			
		||||
    $mask    = lc $mask;
 | 
			
		||||
 | 
			
		||||
    $mask = $self->nick_to_banmask($mask);
 | 
			
		||||
    $self->ban_user($channel, $mode, $mask, $immediately);
 | 
			
		||||
 | 
			
		||||
    my $data = {
 | 
			
		||||
        timeout   => $length > 0 ? gettimeofday + $length : -1,
 | 
			
		||||
        owner     => $owner,
 | 
			
		||||
        reason    => $reason,
 | 
			
		||||
        timestamp => time,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    if ($mode eq 'b') {
 | 
			
		||||
        $self->{banlist}->add($channel, $mask, $data);
 | 
			
		||||
    } elsif ($mode eq 'q') {
 | 
			
		||||
        $self->{quietlist}->add($channel, $mask, $data);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    my $method = $mode eq 'b' ? 'unban' : 'unmute';
 | 
			
		||||
    $self->{pbot}->{timer}->dequeue_event("$method $channel $mask");
 | 
			
		||||
 | 
			
		||||
    if ($length > 0) {
 | 
			
		||||
        $self->enqueue_unban($channel, $mode, $mask, $length);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub checkban {
 | 
			
		||||
    my ($self, $channel, $mode, $mask) = @_;
 | 
			
		||||
    $mask = $self->nick_to_banmask($mask);
 | 
			
		||||
 | 
			
		||||
    my $data;
 | 
			
		||||
 | 
			
		||||
    if ($mode eq 'b') {
 | 
			
		||||
        $data = $self->{banlist}->get_data($channel, $mask);
 | 
			
		||||
    } elsif ($mode eq 'q') {
 | 
			
		||||
        $data = $self->{quietlist}->get_data($channel, $mask);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (not defined $data) {
 | 
			
		||||
        return "$mask is not " . ($mode eq 'b' ? 'banned' : 'muted') . ".";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    my $result = "$mask " . ($mode eq 'b' ? 'banned' : 'quieted') . " in $channel ";
 | 
			
		||||
 | 
			
		||||
    if (defined $data->{timestamp}) {
 | 
			
		||||
        my $date = strftime "%a %b %e %H:%M:%S %Y %Z", localtime $data->{timestamp};
 | 
			
		||||
        my $ago = concise ago (time - $data->{timestamp});
 | 
			
		||||
        $result .= "on $date ($ago ago) ";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $result .= "by $data->{owner} "   if defined $data->{owner};
 | 
			
		||||
    $result .= "for $data->{reason} " if defined $data->{reason};
 | 
			
		||||
    if ($data->{timeout} > 0) {
 | 
			
		||||
        my $duration = concise duration($data->{timeout} - gettimeofday);
 | 
			
		||||
        $result .= "($duration remaining)";
 | 
			
		||||
    }
 | 
			
		||||
    return $result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub add_to_ban_queue {
 | 
			
		||||
    my ($self, $channel, $mode, $mask) = @_;
 | 
			
		||||
    if (not grep { $_ eq $mask } @{$self->{ban_queue}->{$channel}->{$mode}}) {
 | 
			
		||||
        push @{$self->{ban_queue}->{$channel}->{$mode}}, $mask;
 | 
			
		||||
        $self->{pbot}->{logger}->log("Added +$mode $mask for $channel to ban queue.\n");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub flush_ban_queue {
 | 
			
		||||
    my $self = shift;
 | 
			
		||||
 | 
			
		||||
    my $MAX_COMMANDS = 4;
 | 
			
		||||
    my $commands     = 0;
 | 
			
		||||
 | 
			
		||||
    foreach my $channel (keys %{$self->{ban_queue}}) {
 | 
			
		||||
        my $done = 0;
 | 
			
		||||
        while (not $done) {
 | 
			
		||||
            my ($list, $count, $modes);
 | 
			
		||||
            $list  = '';
 | 
			
		||||
            $modes = '+';
 | 
			
		||||
            $count = 0;
 | 
			
		||||
 | 
			
		||||
            foreach my $mode (keys %{$self->{ban_queue}->{$channel}}) {
 | 
			
		||||
                while (@{$self->{ban_queue}->{$channel}->{$mode}}) {
 | 
			
		||||
                    my $target = pop @{$self->{ban_queue}->{$channel}->{$mode}};
 | 
			
		||||
                    $list  .= " $target";
 | 
			
		||||
                    $modes .= $mode;
 | 
			
		||||
                    last if ++$count >= $self->{pbot}->{ircd}->{MODES};
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (not @{$self->{ban_queue}->{$channel}->{$mode}}) {
 | 
			
		||||
                    delete $self->{ban_queue}->{$channel}->{$mode};
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                last if $count >= $self->{pbot}->{ircd}->{MODES};
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (not keys %{$self->{ban_queue}->{$channel}}) {
 | 
			
		||||
                delete $self->{ban_queue}->{$channel};
 | 
			
		||||
                $done = 1;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if ($count) {
 | 
			
		||||
                $self->{pbot}->{chanops}->add_op_command($channel, "mode $channel $modes $list");
 | 
			
		||||
                $self->{pbot}->{chanops}->gain_ops($channel);
 | 
			
		||||
                return if ++$commands >= $MAX_COMMANDS;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub add_to_unban_queue {
 | 
			
		||||
    my ($self, $channel, $mode, $mask) = @_;
 | 
			
		||||
    if (not grep { $_ eq $mask } @{$self->{unban_queue}->{$channel}->{$mode}}) {
 | 
			
		||||
        push @{$self->{unban_queue}->{$channel}->{$mode}}, $mask;
 | 
			
		||||
        $self->{pbot}->{logger}->log("Added -$mode $mask for $channel to unban queue.\n");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub flush_unban_queue {
 | 
			
		||||
    my $self = shift;
 | 
			
		||||
 | 
			
		||||
    my $MAX_COMMANDS = 4;
 | 
			
		||||
    my $commands     = 0;
 | 
			
		||||
 | 
			
		||||
    foreach my $channel (keys %{$self->{unban_queue}}) {
 | 
			
		||||
        my $done = 0;
 | 
			
		||||
        while (not $done) {
 | 
			
		||||
            my ($list, $count, $modes);
 | 
			
		||||
            $list  = '';
 | 
			
		||||
            $modes = '-';
 | 
			
		||||
            $count = 0;
 | 
			
		||||
 | 
			
		||||
            foreach my $mode (keys %{$self->{unban_queue}->{$channel}}) {
 | 
			
		||||
                while (@{$self->{unban_queue}->{$channel}->{$mode}}) {
 | 
			
		||||
                    my $target = pop @{$self->{unban_queue}->{$channel}->{$mode}};
 | 
			
		||||
                    $list  .= " $target";
 | 
			
		||||
                    $modes .= $mode;
 | 
			
		||||
                    last if ++$count >= $self->{pbot}->{ircd}->{MODES};
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (not @{$self->{unban_queue}->{$channel}->{$mode}}) {
 | 
			
		||||
                    delete $self->{unban_queue}->{$channel}->{$mode};
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                last if $count >= $self->{pbot}->{ircd}->{MODES};
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (not keys %{$self->{unban_queue}->{$channel}}) {
 | 
			
		||||
                delete $self->{unban_queue}->{$channel};
 | 
			
		||||
                $done = 1;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if ($count) {
 | 
			
		||||
                $self->{pbot}->{chanops}->add_op_command($channel, "mode $channel $modes $list");
 | 
			
		||||
                $self->{pbot}->{chanops}->gain_ops($channel);
 | 
			
		||||
                return if ++$commands >= $MAX_COMMANDS;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub enqueue_unban {
 | 
			
		||||
    my ($self, $channel, $mode, $hostmask, $interval) = @_;
 | 
			
		||||
 | 
			
		||||
    my $method = $mode eq 'b' ? 'unban' : 'unmute';
 | 
			
		||||
 | 
			
		||||
    $self->{pbot}->{timer}->enqueue_event(
 | 
			
		||||
        sub {
 | 
			
		||||
            $self->{pbot}->{timer}->update_interval("$method $channel $hostmask", 60 * 15, 1); # try again in 15 minutes
 | 
			
		||||
            return if not $self->{pbot}->{joined_channels};
 | 
			
		||||
            $self->unban_user($channel, $mode, $hostmask);
 | 
			
		||||
        }, $interval, "$method $channel $hostmask", 1
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub enqueue_timeouts {
 | 
			
		||||
    my ($self, $list, $mode) = @_;
 | 
			
		||||
    my $now = time;
 | 
			
		||||
 | 
			
		||||
    foreach my $channel ($list->get_keys) {
 | 
			
		||||
        foreach my $mask ($list->get_keys($channel)) {
 | 
			
		||||
            my $timeout = $list->get_data($channel, $mask, 'timeout');
 | 
			
		||||
            next if $timeout <= 0;
 | 
			
		||||
            my $interval = $timeout - $now;
 | 
			
		||||
            $interval = 10 if $interval < 10;
 | 
			
		||||
            $self->enqueue_unban($channel, $mode, $mask, $interval);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub has_ban_timeout {
 | 
			
		||||
    my ($self, $channel, $mask, $mode) = @_;
 | 
			
		||||
    $mode ||= 'b';
 | 
			
		||||
 | 
			
		||||
    my $list = $mode eq 'b' ? $self->{banlist} : $self->{quietlist};
 | 
			
		||||
 | 
			
		||||
    my $data = $list->get_data($channel, $mask);
 | 
			
		||||
 | 
			
		||||
    if (defined $data && $data->{timeout} > 0) {
 | 
			
		||||
        return 1;
 | 
			
		||||
    } else {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub is_banned {
 | 
			
		||||
    my ($self, $nick, $user, $host, $channel) = @_;
 | 
			
		||||
    my ($self, $channel, $nick, $user, $host) = @_;
 | 
			
		||||
 | 
			
		||||
    my $message_account   = $self->{pbot}->{messagehistory}->{database}->get_message_account($nick, $user, $host);
 | 
			
		||||
    my @nickserv_accounts = $self->{pbot}->{messagehistory}->{database}->get_nickserv_accounts($message_account);
 | 
			
		||||
@ -166,18 +728,18 @@ sub is_banned {
 | 
			
		||||
    my $banned = undef;
 | 
			
		||||
 | 
			
		||||
    foreach my $nickserv_account (@nickserv_accounts) {
 | 
			
		||||
        my $baninfos = $self->get_baninfo("$nick!$user\@$host", $channel, $nickserv_account);
 | 
			
		||||
        my $baninfos = $self->get_baninfo($channel, "$nick!$user\@$host", $nickserv_account);
 | 
			
		||||
 | 
			
		||||
        if (defined $baninfos) {
 | 
			
		||||
            foreach my $baninfo (@$baninfos) {
 | 
			
		||||
                my $u           = $self->{pbot}->{users}->loggedin($channel, "$nick!$user\@$host");
 | 
			
		||||
                my $whitelisted = $self->{pbot}->{capabilities}->userhas($u, 'is-whitelisted');
 | 
			
		||||
                if ($self->{pbot}->{antiflood}->ban_exempted($baninfo->{channel}, $baninfo->{banmask}) || $whitelisted) {
 | 
			
		||||
                    $self->{pbot}->{logger}->log("[BanTracker] is_banned: $nick!$user\@$host banned as $baninfo->{banmask} in $baninfo->{channel}, but allowed through whitelist\n");
 | 
			
		||||
                if ($self->{pbot}->{antiflood}->ban_exempted($baninfo->{channel}, $baninfo->{mask}) || $whitelisted) {
 | 
			
		||||
                    $self->{pbot}->{logger}->log("[BanList] is_banned: $nick!$user\@$host banned as $baninfo->{mask} in $baninfo->{channel}, but allowed through whitelist\n");
 | 
			
		||||
                } else {
 | 
			
		||||
                    if ($channel eq lc $baninfo->{channel}) {
 | 
			
		||||
                        my $mode = $baninfo->{type} eq "+b" ? "banned" : "quieted";
 | 
			
		||||
                        $self->{pbot}->{logger}->log("[BanTracker] is_banned: $nick!$user\@$host $mode as $baninfo->{banmask} in $baninfo->{channel} by $baninfo->{owner}\n");
 | 
			
		||||
                        $self->{pbot}->{logger}->log("[BanList] is_banned: $nick!$user\@$host $mode as $baninfo->{mask} in $baninfo->{channel} by $baninfo->{owner}\n");
 | 
			
		||||
                        $banned = $baninfo;
 | 
			
		||||
                        last;
 | 
			
		||||
                    }
 | 
			
		||||
@ -185,46 +747,8 @@ sub is_banned {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return $banned;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub track_mode {
 | 
			
		||||
    my $self = shift;
 | 
			
		||||
    my ($source, $mode, $target, $channel) = @_;
 | 
			
		||||
 | 
			
		||||
    $mode    = lc $mode;
 | 
			
		||||
    $target  = lc $target;
 | 
			
		||||
    $channel = lc $channel;
 | 
			
		||||
 | 
			
		||||
    if ($mode eq "+b" or $mode eq "+q") {
 | 
			
		||||
        $self->{pbot}->{logger}->log("ban-tracker: $target " . ($mode eq '+b' ? 'banned' : 'quieted') . " by $source in $channel.\n");
 | 
			
		||||
        $self->{banlist}->{$channel}->{$mode}->{$target} = [$source, gettimeofday];
 | 
			
		||||
        $self->{pbot}->{antiflood}->devalidate_accounts($target, $channel);
 | 
			
		||||
    } elsif ($mode eq "-b" or $mode eq "-q") {
 | 
			
		||||
        $self->{pbot}->{logger}->log("ban-tracker: $target " . ($mode eq '-b' ? 'unbanned' : 'unquieted') . " by $source in $channel.\n");
 | 
			
		||||
        delete $self->{banlist}->{$channel}->{$mode eq "-b" ? "+b" : "+q"}->{$target};
 | 
			
		||||
 | 
			
		||||
        if ($mode eq "-b") {
 | 
			
		||||
            if ($self->{pbot}->{chanops}->{unban_timeout}->exists($channel, $target)) {
 | 
			
		||||
                $self->{pbot}->{chanops}->{unban_timeout}->remove($channel, $target);
 | 
			
		||||
                $self->{pbot}->{timer}->dequeue_event("unban_timeout $channel $target");
 | 
			
		||||
            }
 | 
			
		||||
            elsif ($self->{pbot}->{chanops}->{unban_timeout}->exists($channel, "$target\$##stop_join_flood")) {
 | 
			
		||||
                # freenode strips channel forwards from unban result if no ban exists with a channel forward
 | 
			
		||||
                $self->{pbot}->{chanops}->{unban_timeout}->remove($channel, "$target\$##stop_join_flood");
 | 
			
		||||
                $self->{pbot}->{timer}->dequeue_event(lc "unban_timeout $channel $target\$##stop_join_flood");
 | 
			
		||||
            }
 | 
			
		||||
        } elsif ($mode eq "-q") {
 | 
			
		||||
            if ($self->{pbot}->{chanops}->{unmute_timeout}->exists($channel, $target)) {
 | 
			
		||||
                $self->{pbot}->{chanops}->{unmute_timeout}->remove($channel, $target);
 | 
			
		||||
                $self->{pbot}->{timer}->dequeue_event("unmute_timeout $channel $target");
 | 
			
		||||
            } else {
 | 
			
		||||
                $self->{pbot}->{logger}->log("No unmute timeout for $channel $target\n");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        $self->{pbot}->{logger}->log("BanTracker: Unknown mode '$mode'\n");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
1;
 | 
			
		||||
 | 
			
		||||
@ -26,8 +26,6 @@ sub initialize {
 | 
			
		||||
    $self->{pbot}->{commands}->register(sub { $self->mute_user(@_) },    "mute",      1);
 | 
			
		||||
    $self->{pbot}->{commands}->register(sub { $self->unmute_user(@_) },  "unmute",    1);
 | 
			
		||||
    $self->{pbot}->{commands}->register(sub { $self->kick_user(@_) },    "kick",      1);
 | 
			
		||||
    $self->{pbot}->{commands}->register(sub { $self->checkban(@_) },     "checkban",  0);
 | 
			
		||||
    $self->{pbot}->{commands}->register(sub { $self->checkmute(@_) },    "checkmute", 0);
 | 
			
		||||
    $self->{pbot}->{commands}->register(sub { $self->op_user(@_) },      "op",        1);
 | 
			
		||||
    $self->{pbot}->{commands}->register(sub { $self->deop_user(@_) },    "deop",      1);
 | 
			
		||||
    $self->{pbot}->{commands}->register(sub { $self->voice_user(@_) },   "voice",     1);
 | 
			
		||||
@ -337,28 +335,6 @@ sub mode {
 | 
			
		||||
    else                  { return ""; }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub checkban {
 | 
			
		||||
    my ($self, $from, $nick, $user, $host, $arguments, $stuff) = @_;
 | 
			
		||||
    my ($target, $channel) = $self->{pbot}->{interpreter}->split_args($stuff->{arglist}, 2);
 | 
			
		||||
 | 
			
		||||
    return "Usage: checkban <mask> [channel]" if not defined $target;
 | 
			
		||||
    $channel = $from if not defined $channel;
 | 
			
		||||
 | 
			
		||||
    return "Please specify a channel." if $channel !~ /^#/;
 | 
			
		||||
    return $self->{pbot}->{chanops}->checkban($channel, $target);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub checkmute {
 | 
			
		||||
    my ($self, $from, $nick, $user, $host, $arguments, $stuff) = @_;
 | 
			
		||||
    my ($target, $channel) = $self->{pbot}->{interpreter}->split_args($stuff->{arglist}, 2);
 | 
			
		||||
 | 
			
		||||
    return "Usage: checkmute <mask> [channel]" if not defined $target;
 | 
			
		||||
    $channel = $from if not defined $channel;
 | 
			
		||||
 | 
			
		||||
    return "Please specify a channel." if $channel !~ /^#/;
 | 
			
		||||
    return $self->{pbot}->{chanops}->checkmute($channel, $target);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub ban_user {
 | 
			
		||||
    my ($self, $from, $nick, $user, $host, $arguments, $stuff) = @_;
 | 
			
		||||
    my ($target, $channel, $length) = $self->{pbot}->{interpreter}->split_args($stuff->{arglist}, 3);
 | 
			
		||||
@ -383,6 +359,7 @@ sub ban_user {
 | 
			
		||||
 | 
			
		||||
    my $no_length = 0;
 | 
			
		||||
    if (not defined $length) {
 | 
			
		||||
        # TODO: user account length override
 | 
			
		||||
        $length = $self->{pbot}->{registry}->get_value($channel, 'default_ban_timeout', 0, $stuff)
 | 
			
		||||
          // $self->{pbot}->{registry}->get_value('general', 'default_ban_timeout', 0, $stuff) // 60 * 60 * 24;    # 24 hours
 | 
			
		||||
        $no_length = 1;
 | 
			
		||||
@ -405,15 +382,16 @@ sub ban_user {
 | 
			
		||||
    my $duration;
 | 
			
		||||
 | 
			
		||||
    foreach my $t (@targets) {
 | 
			
		||||
        my $mask = lc $self->{pbot}->{chanops}->nick_to_banmask($t);
 | 
			
		||||
        my $mask = lc $self->{pbot}->{banlist}->nick_to_banmask($t);
 | 
			
		||||
 | 
			
		||||
        if ($no_length && $self->{pbot}->{chanops}->{unban_timeout}->exists($channel, $mask)) {
 | 
			
		||||
            my $timeout = $self->{pbot}->{chanops}->{unban_timeout}->get_data($channel, $mask, 'timeout');
 | 
			
		||||
            my $d       = duration($timeout - gettimeofday);
 | 
			
		||||
        my $timeout = $self->{pbot}->{banlist}->{banlist}->get_data($channel, $mask, 'timeout') // 0;
 | 
			
		||||
 | 
			
		||||
        if ($no_length && $timeout > 0) {
 | 
			
		||||
            my $d = duration($timeout - gettimeofday);
 | 
			
		||||
            $result .= "$sep$mask has $d remaining on their $channel ban";
 | 
			
		||||
            $sep = '; ';
 | 
			
		||||
        } else {
 | 
			
		||||
            $self->{pbot}->{chanops}->ban_user_timed("$nick!$user\@$host", undef, $mask, $channel, $length, $immediately);
 | 
			
		||||
            $self->{pbot}->{banlist}->ban_user_timed($channel, 'b', $mask, $length, "$nick!$user\@$host", undef, $immediately);
 | 
			
		||||
            $duration = $length > 0 ? duration $length : 'all eternity';
 | 
			
		||||
            if ($immediately) {
 | 
			
		||||
                $result .= "$sep$mask banned in $channel for $duration";
 | 
			
		||||
@ -427,7 +405,7 @@ sub ban_user {
 | 
			
		||||
 | 
			
		||||
    if (not $immediately) {
 | 
			
		||||
        $result .= " banned in $channel for $duration";
 | 
			
		||||
        $self->{pbot}->{chanops}->check_ban_queue;
 | 
			
		||||
        $self->{pbot}->{banlist}->flush_ban_queue;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $result = "/msg $nick $result" if $result !~ m/remaining on their/;
 | 
			
		||||
@ -468,17 +446,19 @@ sub unban_user {
 | 
			
		||||
                return "/msg $nick Clearing the channel bans requires the can-clear-bans capability, which your user account does not have.";
 | 
			
		||||
            }
 | 
			
		||||
            $channel = lc $channel;
 | 
			
		||||
            if (exists $self->{pbot}->{bantracker}->{banlist}->{$channel} && exists $self->{pbot}->{bantracker}->{banlist}->{$channel}->{'+b'}) {
 | 
			
		||||
            if ($self->{pbot}->{banlist}->{banlist}->exists($channel)) {
 | 
			
		||||
                $immediately = 0;
 | 
			
		||||
                foreach my $banmask (keys %{$self->{pbot}->{bantracker}->{banlist}->{$channel}->{'+b'}}) { $self->{pbot}->{chanops}->unban_user($banmask, $channel, $immediately); }
 | 
			
		||||
                foreach my $banmask ($self->{pbot}->{banlist}->{banlist}->get_keys($channel)) {
 | 
			
		||||
                    $self->{pbot}->{banlist}->unban_user($banmask, 'b', $channel, $immediately);
 | 
			
		||||
                }
 | 
			
		||||
                last;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            $self->{pbot}->{chanops}->unban_user($t, $channel, $immediately);
 | 
			
		||||
            $self->{pbot}->{banlist}->unban_user($t, 'b', $channel, $immediately);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $self->{pbot}->{chanops}->check_unban_queue if not $immediately;
 | 
			
		||||
    $self->{pbot}->{banlist}->flush_unban_queue if not $immediately;
 | 
			
		||||
    return "/msg $nick $target has been unbanned from $channel.";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -531,15 +511,16 @@ sub mute_user {
 | 
			
		||||
    my $duration;
 | 
			
		||||
 | 
			
		||||
    foreach my $t (@targets) {
 | 
			
		||||
        my $mask = lc $self->{pbot}->{chanops}->nick_to_banmask($t);
 | 
			
		||||
        my $mask = lc $self->{pbot}->{banlist}->nick_to_banmask($t);
 | 
			
		||||
 | 
			
		||||
        if ($no_length && $self->{pbot}->{chanops}->{unmute_timeout}->exists($channel, $mask)) {
 | 
			
		||||
            my $timeout = $self->{pbot}->{chanops}->{unmute_timeout}->get_data($channel, $mask, 'timeout');
 | 
			
		||||
            my $d       = duration($timeout - gettimeofday);
 | 
			
		||||
        my $timeout = $self->{pbot}->{banlist}->{quietlist}->get_data($channel, $mask, 'timeout') // 0;
 | 
			
		||||
 | 
			
		||||
        if ($no_length && $timeout > 0) {
 | 
			
		||||
            my $d = duration($timeout - gettimeofday);
 | 
			
		||||
            $result .= "$sep$mask has $d remaining on their $channel mute";
 | 
			
		||||
            $sep = '; ';
 | 
			
		||||
        } else {
 | 
			
		||||
            $self->{pbot}->{chanops}->mute_user_timed("$nick!$user\@$host", undef, $t, $channel, $length, $immediately);
 | 
			
		||||
            $self->{pbot}->{banlist}->ban_user_timed($channel, 'q', $t, $length, "$nick!$user\@$host", undef, $immediately);
 | 
			
		||||
            $duration = $length > 0 ? duration $length : 'all eternity';
 | 
			
		||||
            if ($immediately) {
 | 
			
		||||
                $result .= "$sep$mask muted in $channel for $duration";
 | 
			
		||||
@ -553,7 +534,7 @@ sub mute_user {
 | 
			
		||||
 | 
			
		||||
    if (not $immediately) {
 | 
			
		||||
        $result .= " muted in $channel for $duration";
 | 
			
		||||
        $self->{pbot}->{chanops}->check_ban_queue;
 | 
			
		||||
        $self->{pbot}->{banlist}->flush_ban_queue;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $result = "/msg $nick $result" if $result !~ m/remaining on their/;
 | 
			
		||||
@ -594,17 +575,19 @@ sub unmute_user {
 | 
			
		||||
                return "/msg $nick Clearing the channel mutes requires the can-clear-mutes capability, which your user account does not have.";
 | 
			
		||||
            }
 | 
			
		||||
            $channel = lc $channel;
 | 
			
		||||
            if (exists $self->{pbot}->{bantracker}->{banlist}->{$channel} && exists $self->{pbot}->{bantracker}->{banlist}->{$channel}->{'+q'}) {
 | 
			
		||||
            if ($self->{pbot}->{banlist}->{quietlist}->exists($channel)) {
 | 
			
		||||
                $immediately = 0;
 | 
			
		||||
                foreach my $banmask (keys %{$self->{pbot}->{bantracker}->{banlist}->{$channel}->{'+q'}}) { $self->{pbot}->{chanops}->unmute_user($banmask, $channel, $immediately); }
 | 
			
		||||
                foreach my $banmask ($self->{pbot}->{banlist}->{quietlist}->get_keys($channel)) {
 | 
			
		||||
                    $self->{pbot}->{banlist}->unban_user($channel, 'q', $banmask, $immediately);
 | 
			
		||||
                }
 | 
			
		||||
                last;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            $self->{pbot}->{chanops}->unmute_user($t, $channel, $immediately);
 | 
			
		||||
            $self->{pbot}->{banlist}->unban_user($channel, 'q', $t, $immediately);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $self->{pbot}->{chanops}->check_unban_queue if not $immediately;
 | 
			
		||||
    $self->{pbot}->{banlist}->flush_unban_queue if not $immediately;
 | 
			
		||||
    return "/msg $nick $target has been unmuted in $channel.";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										427
									
								
								PBot/ChanOps.pm
									
									
									
									
									
								
							
							
						
						
									
										427
									
								
								PBot/ChanOps.pm
									
									
									
									
									
								
							@ -21,27 +21,6 @@ use Time::Duration qw(concise duration);
 | 
			
		||||
sub initialize {
 | 
			
		||||
    my ($self, %conf) = @_;
 | 
			
		||||
 | 
			
		||||
    $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->enqueue_timeouts;
 | 
			
		||||
 | 
			
		||||
    $self->{ban_queue}   = {};
 | 
			
		||||
    $self->{unban_queue} = {};
 | 
			
		||||
 | 
			
		||||
    $self->{op_commands}  = {};
 | 
			
		||||
    $self->{is_opped}     = {};
 | 
			
		||||
    $self->{op_requested} = {};
 | 
			
		||||
@ -51,7 +30,28 @@ sub initialize {
 | 
			
		||||
    $self->{pbot}->{registry}->add_default('text', 'general', 'deop_timeout', 300);
 | 
			
		||||
 | 
			
		||||
    $self->{pbot}->{timer}->register(sub { $self->check_opped_timeouts },  10, 'Check Opped Timeouts');
 | 
			
		||||
    $self->{pbot}->{timer}->register(sub { $self->check_unban_queue },     30, 'Check Unban Queue');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub track_mode {
 | 
			
		||||
    my ($self, $source, $channel, $mode, $target) = @_;
 | 
			
		||||
 | 
			
		||||
    $channel = lc $channel;
 | 
			
		||||
    $target  = lc $target;
 | 
			
		||||
 | 
			
		||||
    if ($target eq lc $self->{pbot}->{registry}->get_value('irc', 'botnick')) {
 | 
			
		||||
        if ($mode eq '+o') {
 | 
			
		||||
            $self->{pbot}->{logger}->log("$source opped me in $channel\n");
 | 
			
		||||
            my $timeout = $self->{pbot}->{registry}->get_value($channel, 'deop_timeout') // $self->{pbot}->{registry}->get_value('general', 'deop_timeout');
 | 
			
		||||
            $self->{is_opped}->{$channel}{timeout} = gettimeofday + $timeout;
 | 
			
		||||
            delete $self->{op_requested}->{$channel};
 | 
			
		||||
            $self->perform_op_commands($channel);
 | 
			
		||||
        } elsif ($mode eq '-o') {
 | 
			
		||||
            $self->{pbot}->{logger}->log("$source removed my ops in $channel\n");
 | 
			
		||||
            delete $self->{is_opped}->{$channel};
 | 
			
		||||
        } else {
 | 
			
		||||
            $self->{pbot}->{logger}->log("ChanOps: $source performed unhandled mode '$mode' on me\n");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub can_gain_ops {
 | 
			
		||||
@ -121,389 +121,6 @@ sub perform_op_commands {
 | 
			
		||||
    $self->{pbot}->{logger}->log("Done.\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub ban_user {
 | 
			
		||||
    my $self = shift;
 | 
			
		||||
    my ($mask, $channel, $immediately) = @_;
 | 
			
		||||
    $self->add_to_ban_queue($channel, 'b', $mask);
 | 
			
		||||
    if (not defined $immediately or $immediately != 0) { $self->check_ban_queue; }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub get_bans {
 | 
			
		||||
    my ($self, $mask, $channel) = @_;
 | 
			
		||||
    my $masks;
 | 
			
		||||
 | 
			
		||||
    if ($mask !~ m/[!@\$]/) {
 | 
			
		||||
        my ($message_account, $hostmask) = $self->{pbot}->{messagehistory}->{database}->find_message_account_by_nick($mask);
 | 
			
		||||
 | 
			
		||||
        if (defined $hostmask) {
 | 
			
		||||
            my $nickserv = $self->{pbot}->{messagehistory}->{database}->get_current_nickserv_account($message_account);
 | 
			
		||||
            $masks = $self->{pbot}->{bantracker}->get_baninfo($hostmask, $channel, $nickserv);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        my %akas = $self->{pbot}->{messagehistory}->{database}->get_also_known_as($mask);
 | 
			
		||||
 | 
			
		||||
        foreach my $aka (keys %akas) {
 | 
			
		||||
            next if $akas{$aka}->{type} == $self->{pbot}->{messagehistory}->{database}->{alias_type}->{WEAK};
 | 
			
		||||
            next if $akas{$aka}->{nickchange} == 1;
 | 
			
		||||
 | 
			
		||||
            my $b = $self->{pbot}->{bantracker}->get_baninfo($aka, $channel);
 | 
			
		||||
            if (defined $b) {
 | 
			
		||||
                $masks = {} if not defined $masks;
 | 
			
		||||
                push @$masks, @$b;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return $masks;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub unmode_user {
 | 
			
		||||
    my ($self, $mask, $channel, $immediately, $mode) = @_;
 | 
			
		||||
 | 
			
		||||
    $mask    = lc $mask;
 | 
			
		||||
    $channel = lc $channel;
 | 
			
		||||
    $self->{pbot}->{logger}->log("Removing mode $mode from $mask in $channel\n");
 | 
			
		||||
 | 
			
		||||
    my $bans = $self->get_bans($mask, $channel);
 | 
			
		||||
    my %unbanned;
 | 
			
		||||
 | 
			
		||||
    if (not defined $bans) {
 | 
			
		||||
        my $baninfo = {};
 | 
			
		||||
        $baninfo->{banmask} = $mask;
 | 
			
		||||
        $baninfo->{type}    = '+' . $mode;
 | 
			
		||||
        push @$bans, $baninfo;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    foreach my $baninfo (@$bans) {
 | 
			
		||||
        next if $baninfo->{type} ne '+' . $mode;
 | 
			
		||||
        next if exists $unbanned{$baninfo->{banmask}};
 | 
			
		||||
        $unbanned{$baninfo->{banmask}} = 1;
 | 
			
		||||
        $self->add_to_unban_queue($channel, $mode, $baninfo->{banmask});
 | 
			
		||||
    }
 | 
			
		||||
    $self->check_unban_queue if $immediately;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub nick_to_banmask {
 | 
			
		||||
    my ($self, $mask) = @_;
 | 
			
		||||
 | 
			
		||||
    if ($mask !~ m/[!@\$]/) {
 | 
			
		||||
        my ($message_account, $hostmask) = $self->{pbot}->{messagehistory}->{database}->find_message_account_by_nick($mask);
 | 
			
		||||
        if (defined $hostmask) {
 | 
			
		||||
            my $nickserv = $self->{pbot}->{messagehistory}->{database}->get_current_nickserv_account($message_account);
 | 
			
		||||
            if (defined $nickserv && length $nickserv) { $mask = '$a:' . $nickserv; }
 | 
			
		||||
            else {
 | 
			
		||||
                my ($nick, $user, $host) = $hostmask =~ m/([^!]+)!([^@]+)@(.*)/;
 | 
			
		||||
                $mask = "*!$user\@" . $self->{pbot}->{antiflood}->address_to_mask($host);
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            $mask .= '!*@*';
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return $mask;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub unban_user {
 | 
			
		||||
    my ($self, $mask, $channel, $immediately) = @_;
 | 
			
		||||
    $mask    = lc $mask;
 | 
			
		||||
    $channel = lc $channel;
 | 
			
		||||
    $self->{pbot}->{logger}->log("Unbanning $channel $mask\n");
 | 
			
		||||
    $self->unmode_user($mask, $channel, $immediately, 'b');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub ban_user_timed {
 | 
			
		||||
    my ($self, $owner, $reason, $mask, $channel, $length, $immediately) = @_;
 | 
			
		||||
 | 
			
		||||
    $channel = lc $channel;
 | 
			
		||||
    $mask    = lc $mask;
 | 
			
		||||
 | 
			
		||||
    $mask = $self->nick_to_banmask($mask);
 | 
			
		||||
    $self->ban_user($mask, $channel, $immediately);
 | 
			
		||||
 | 
			
		||||
    my $data = {};
 | 
			
		||||
    $data->{timeout} = $length > 0 ? gettimeofday + $length : -1;
 | 
			
		||||
    $data->{owner}   = $owner  if defined $owner;
 | 
			
		||||
    $data->{reason}  = $reason if defined $reason;
 | 
			
		||||
    $self->{unban_timeout}->add($channel, $mask, $data);
 | 
			
		||||
 | 
			
		||||
    $self->{pbot}->{timer}->dequeue_event("unban_timeout $channel $mask");
 | 
			
		||||
 | 
			
		||||
    if ($length > 0) {
 | 
			
		||||
        $self->enqueue_unban_timeout($channel, $mask, $length);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub checkban {
 | 
			
		||||
    my ($self, $channel, $target) = @_;
 | 
			
		||||
    my $mask = $self->nick_to_banmask($target);
 | 
			
		||||
 | 
			
		||||
    if ($self->{unban_timeout}->exists($channel, $mask)) {
 | 
			
		||||
        my $timeout = $self->{unban_timeout}->get_data($channel, $mask, 'timeout');
 | 
			
		||||
        my $owner   = $self->{unban_timeout}->get_data($channel, $mask, 'owner');
 | 
			
		||||
        my $reason  = $self->{unban_timeout}->get_data($channel, $mask, 'reason');
 | 
			
		||||
        my $duration = concise duration($timeout - gettimeofday);
 | 
			
		||||
 | 
			
		||||
        my $result = "$mask banned in $channel ";
 | 
			
		||||
 | 
			
		||||
        $result .= "by $owner "   if defined $owner;
 | 
			
		||||
        $result .= "for $reason " if defined $reason;
 | 
			
		||||
        $result .= $timeout > 0 ? "($duration remaining)" : "(permanent)";
 | 
			
		||||
        return $result;
 | 
			
		||||
    } else {
 | 
			
		||||
        return "$mask has no ban timeout.";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub mute_user {
 | 
			
		||||
    my $self = shift;
 | 
			
		||||
    my ($mask, $channel, $immediately) = @_;
 | 
			
		||||
    $self->add_to_ban_queue($channel, 'q', $mask);
 | 
			
		||||
    if (not defined $immediately or $immediately != 0) { $self->check_ban_queue; }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub unmute_user {
 | 
			
		||||
    my ($self, $mask, $channel, $immediately) = @_;
 | 
			
		||||
    $mask    = lc $mask;
 | 
			
		||||
    $channel = lc $channel;
 | 
			
		||||
    $self->{pbot}->{logger}->log("Unmuting $channel $mask\n");
 | 
			
		||||
    $self->unmode_user($mask, $channel, $immediately, 'q');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub mute_user_timed {
 | 
			
		||||
    my $self = shift;
 | 
			
		||||
    my ($owner, $reason, $mask, $channel, $length, $immediately) = @_;
 | 
			
		||||
 | 
			
		||||
    $mask = $self->nick_to_banmask($mask);
 | 
			
		||||
    $self->mute_user($mask, $channel, $immediately);
 | 
			
		||||
 | 
			
		||||
    my $data = {};
 | 
			
		||||
    $data->{timeout} = $length > 0 ? gettimeofday + $length : -1;
 | 
			
		||||
    $data->{owner}   = $owner  if defined $owner;
 | 
			
		||||
    $data->{reason}  = $reason if defined $reason;
 | 
			
		||||
    $self->{unmute_timeout}->add($channel, $mask, $data);
 | 
			
		||||
 | 
			
		||||
    $self->{pbot}->{timer}->dequeue_event("unmute_timeout $channel $mask");
 | 
			
		||||
 | 
			
		||||
    if ($length > 0) {
 | 
			
		||||
        $self->enqueue_unmute_timeout($channel, $mask, $length);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub checkmute {
 | 
			
		||||
    my ($self, $channel, $target) = @_;
 | 
			
		||||
    my $mask = $self->nick_to_banmask($target);
 | 
			
		||||
 | 
			
		||||
    if ($self->{unmute_timeout}->exists($channel, $mask)) {
 | 
			
		||||
        my $timeout = $self->{unmute_timeout}->get_data($channel, $mask, 'timeout');
 | 
			
		||||
        my $owner   = $self->{unmute_timeout}->get_data($channel, $mask, 'owner');
 | 
			
		||||
        my $reason  = $self->{unmute_timeout}->get_data($channel, $mask, 'reason');
 | 
			
		||||
        my $duration = concise duration($timeout - gettimeofday);
 | 
			
		||||
 | 
			
		||||
        my $result = "$mask muted in $channel ";
 | 
			
		||||
 | 
			
		||||
        $result .= "by $owner "   if defined $owner;
 | 
			
		||||
        $result .= "for $reason " if defined $reason;
 | 
			
		||||
        $result .= $timeout > 0 ? "($duration remaining)" : "(permanent)";
 | 
			
		||||
 | 
			
		||||
        return $result;
 | 
			
		||||
    } else {
 | 
			
		||||
        return "$mask has no mute timeout.";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub join_channel {
 | 
			
		||||
    my ($self, $channels) = @_;
 | 
			
		||||
 | 
			
		||||
    $self->{pbot}->{conn}->join($channels);
 | 
			
		||||
 | 
			
		||||
    foreach my $channel (split /,/, $channels) {
 | 
			
		||||
        $channel = lc $channel;
 | 
			
		||||
        $self->{pbot}->{event_dispatcher}->dispatch_event('pbot.join', {channel => $channel});
 | 
			
		||||
 | 
			
		||||
        delete $self->{is_opped}->{$channel};
 | 
			
		||||
        delete $self->{op_requested}->{$channel};
 | 
			
		||||
 | 
			
		||||
        if ($self->{pbot}->{channels}->{channels}->exists($channel) and $self->{pbot}->{channels}->{channels}->get_data($channel, 'permop')) { $self->gain_ops($channel); }
 | 
			
		||||
 | 
			
		||||
        $self->{pbot}->{conn}->mode($channel);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub part_channel {
 | 
			
		||||
    my ($self, $channel) = @_;
 | 
			
		||||
    $channel = lc $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 $self->{unban_timeout}->exists($channel, $mask);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub has_mute_timeout {
 | 
			
		||||
    my ($self, $channel, $mask) = @_;
 | 
			
		||||
    return $self->{unmute_timeout}->exists($channel, $mask);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub add_to_ban_queue {
 | 
			
		||||
    my ($self, $channel, $mode, $target) = @_;
 | 
			
		||||
    push @{$self->{ban_queue}->{$channel}->{$mode}}, $target;
 | 
			
		||||
    $self->{pbot}->{logger}->log("Added +$mode $target for $channel to ban queue.\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub check_ban_queue {
 | 
			
		||||
    my $self = shift;
 | 
			
		||||
 | 
			
		||||
    my $MAX_COMMANDS = 4;
 | 
			
		||||
    my $commands     = 0;
 | 
			
		||||
 | 
			
		||||
    foreach my $channel (keys %{$self->{ban_queue}}) {
 | 
			
		||||
        my $done = 0;
 | 
			
		||||
        while (not $done) {
 | 
			
		||||
            my ($list, $count, $modes);
 | 
			
		||||
            $list  = '';
 | 
			
		||||
            $modes = '+';
 | 
			
		||||
            $count = 0;
 | 
			
		||||
 | 
			
		||||
            foreach my $mode (keys %{$self->{ban_queue}->{$channel}}) {
 | 
			
		||||
                while (@{$self->{ban_queue}->{$channel}->{$mode}}) {
 | 
			
		||||
                    my $target = pop @{$self->{ban_queue}->{$channel}->{$mode}};
 | 
			
		||||
                    $list  .= " $target";
 | 
			
		||||
                    $modes .= $mode;
 | 
			
		||||
                    last if ++$count >= $self->{pbot}->{ircd}->{MODES};
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (not @{$self->{ban_queue}->{$channel}->{$mode}}) { delete $self->{ban_queue}->{$channel}->{$mode}; }
 | 
			
		||||
 | 
			
		||||
                last if $count >= $self->{pbot}->{ircd}->{MODES};
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (not keys %{$self->{ban_queue}->{$channel}}) {
 | 
			
		||||
                delete $self->{ban_queue}->{$channel};
 | 
			
		||||
                $done = 1;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if ($count) {
 | 
			
		||||
                $self->add_op_command($channel, "mode $channel $modes $list");
 | 
			
		||||
                $self->gain_ops($channel);
 | 
			
		||||
 | 
			
		||||
                return if ++$commands >= $MAX_COMMANDS;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub add_to_unban_queue {
 | 
			
		||||
    my ($self, $channel, $mode, $target) = @_;
 | 
			
		||||
    if (not grep { $_ eq $target } @{$self->{unban_queue}->{$channel}->{$mode}}) {
 | 
			
		||||
        push @{$self->{unban_queue}->{$channel}->{$mode}}, $target;
 | 
			
		||||
        $self->{pbot}->{logger}->log("Added -$mode $target for $channel to unban queue.\n");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub check_unban_queue {
 | 
			
		||||
    my $self = shift;
 | 
			
		||||
 | 
			
		||||
    my $MAX_COMMANDS = 4;
 | 
			
		||||
    my $commands     = 0;
 | 
			
		||||
 | 
			
		||||
    foreach my $channel (keys %{$self->{unban_queue}}) {
 | 
			
		||||
        my $done = 0;
 | 
			
		||||
        while (not $done) {
 | 
			
		||||
            my ($list, $count, $modes);
 | 
			
		||||
            $list  = '';
 | 
			
		||||
            $modes = '-';
 | 
			
		||||
            $count = 0;
 | 
			
		||||
 | 
			
		||||
            foreach my $mode (keys %{$self->{unban_queue}->{$channel}}) {
 | 
			
		||||
                while (@{$self->{unban_queue}->{$channel}->{$mode}}) {
 | 
			
		||||
                    my $target = pop @{$self->{unban_queue}->{$channel}->{$mode}};
 | 
			
		||||
                    $list  .= " $target";
 | 
			
		||||
                    $modes .= $mode;
 | 
			
		||||
                    last if ++$count >= $self->{pbot}->{ircd}->{MODES};
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (not @{$self->{unban_queue}->{$channel}->{$mode}}) { delete $self->{unban_queue}->{$channel}->{$mode}; }
 | 
			
		||||
 | 
			
		||||
                last if $count >= $self->{pbot}->{ircd}->{MODES};
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (not keys %{$self->{unban_queue}->{$channel}}) {
 | 
			
		||||
                delete $self->{unban_queue}->{$channel};
 | 
			
		||||
                $done = 1;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if ($count) {
 | 
			
		||||
                $self->add_op_command($channel, "mode $channel $modes $list");
 | 
			
		||||
                $self->gain_ops($channel);
 | 
			
		||||
 | 
			
		||||
                return if ++$commands >= $MAX_COMMANDS;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub enqueue_unmute_timeout {
 | 
			
		||||
    my ($self, $channel, $hostmask, $interval) = @_;
 | 
			
		||||
 | 
			
		||||
    $self->{pbot}->{timer}->enqueue_event(
 | 
			
		||||
        sub {
 | 
			
		||||
            return if not $self->{pbot}->{joined_channels};
 | 
			
		||||
            $self->{pbot}->{timer}->update_interval("unmute_timeout $channel $hostmask", 60 * 15, 1); # try again in 15 minutes
 | 
			
		||||
            $self->unmute_user($hostmask, $channel);
 | 
			
		||||
        }, $interval, "unmute_timeout $channel $hostmask", 1
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub enqueue_unban_timeout {
 | 
			
		||||
    my ($self, $channel, $hostmask, $interval) = @_;
 | 
			
		||||
 | 
			
		||||
    $self->{pbot}->{timer}->enqueue_event(
 | 
			
		||||
        sub {
 | 
			
		||||
            return if not $self->{pbot}->{joined_channels};
 | 
			
		||||
            $self->{pbot}->{timer}->update_interval("unban_timeout $channel $hostmask", 60 * 15, 1); # try again in 15 minutes
 | 
			
		||||
            $self->unban_user($hostmask, $channel);
 | 
			
		||||
        }, $interval, "unban_timeout $channel $hostmask", 1
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub enqueue_unmute_timeouts {
 | 
			
		||||
    my ($self) = @_;
 | 
			
		||||
    my $now = time;
 | 
			
		||||
 | 
			
		||||
    foreach my $channel ($self->{unmute_timeout}->get_keys) {
 | 
			
		||||
        foreach my $mask ($self->{unmute_timeout}->get_keys($channel)) {
 | 
			
		||||
            my $timeout = $self->{unmute_timeout}->get_data($channel, $mask, 'timeout');
 | 
			
		||||
            next if $timeout <= 0;
 | 
			
		||||
            my $interval = $timeout - $now;
 | 
			
		||||
            $interval = 10 if $interval < 10;
 | 
			
		||||
            $self->enqueue_unmute_timeout($channel, $mask, $interval);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub enqueue_unban_timeouts {
 | 
			
		||||
    my ($self) = @_;
 | 
			
		||||
    my $now = time;
 | 
			
		||||
 | 
			
		||||
    foreach my $channel ($self->{unban_timeout}->get_keys) {
 | 
			
		||||
        foreach my $mask ($self->{unban_timeout}->get_keys($channel)) {
 | 
			
		||||
            my $timeout = $self->{unban_timeout}->get_data($channel, $mask, 'timeout');
 | 
			
		||||
            next if $timeout <= 0;
 | 
			
		||||
            my $interval = $timeout - $now;
 | 
			
		||||
            $interval = 10 if $interval < 10;
 | 
			
		||||
            $self->enqueue_unban_timeout($channel, $mask, $interval);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub enqueue_timeouts {
 | 
			
		||||
    my ($self) = @_;
 | 
			
		||||
    $self->enqueue_unmute_timeouts;
 | 
			
		||||
    $self->enqueue_unban_timeouts;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub check_opped_timeouts {
 | 
			
		||||
    my $self = shift;
 | 
			
		||||
    my $now  = gettimeofday();
 | 
			
		||||
 | 
			
		||||
@ -18,34 +18,34 @@ sub initialize {
 | 
			
		||||
    $self->{channels} = PBot::HashObject->new(pbot => $self->{pbot}, name => 'Channels', filename => $conf{filename});
 | 
			
		||||
    $self->{channels}->load;
 | 
			
		||||
 | 
			
		||||
    $self->{pbot}->{commands}->register(sub { $self->join(@_) },   "join",      1);
 | 
			
		||||
    $self->{pbot}->{commands}->register(sub { $self->part(@_) },   "part",      1);
 | 
			
		||||
    $self->{pbot}->{commands}->register(sub { $self->set(@_) },    "chanset",   1);
 | 
			
		||||
    $self->{pbot}->{commands}->register(sub { $self->unset(@_) },  "chanunset", 1);
 | 
			
		||||
    $self->{pbot}->{commands}->register(sub { $self->add(@_) },    "chanadd",   1);
 | 
			
		||||
    $self->{pbot}->{commands}->register(sub { $self->remove(@_) }, "chanrem",   1);
 | 
			
		||||
    $self->{pbot}->{commands}->register(sub { $self->list(@_) },   "chanlist",  1);
 | 
			
		||||
    $self->{pbot}->{commands}->register(sub { $self->join_cmd(@_) }, "join",      1);
 | 
			
		||||
    $self->{pbot}->{commands}->register(sub { $self->part_cmd(@_) }, "part",      1);
 | 
			
		||||
    $self->{pbot}->{commands}->register(sub { $self->set(@_) },      "chanset",   1);
 | 
			
		||||
    $self->{pbot}->{commands}->register(sub { $self->unset(@_) },    "chanunset", 1);
 | 
			
		||||
    $self->{pbot}->{commands}->register(sub { $self->add(@_) },      "chanadd",   1);
 | 
			
		||||
    $self->{pbot}->{commands}->register(sub { $self->remove(@_) },   "chanrem",   1);
 | 
			
		||||
    $self->{pbot}->{commands}->register(sub { $self->list(@_) },     "chanlist",  1);
 | 
			
		||||
 | 
			
		||||
    $self->{pbot}->{capabilities}->add('admin', 'can-join',     1);
 | 
			
		||||
    $self->{pbot}->{capabilities}->add('admin', 'can-part',     1);
 | 
			
		||||
    $self->{pbot}->{capabilities}->add('admin', 'can-chanlist', 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub join {
 | 
			
		||||
sub join_cmd {
 | 
			
		||||
    my ($self, $from, $nick, $user, $host, $arguments) = @_;
 | 
			
		||||
    foreach my $channel (split /[\s+,]/, $arguments) {
 | 
			
		||||
        $self->{pbot}->{logger}->log("$nick!$user\@$host made me join $channel\n");
 | 
			
		||||
        $self->{pbot}->{chanops}->join_channel($channel);
 | 
			
		||||
        $self->join($channel);
 | 
			
		||||
    }
 | 
			
		||||
    return "/msg $nick Joining $arguments";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub part {
 | 
			
		||||
sub part_cmd {
 | 
			
		||||
    my ($self, $from, $nick, $user, $host, $arguments) = @_;
 | 
			
		||||
    $arguments = $from if not $arguments;
 | 
			
		||||
    foreach my $channel (split /[\s+,]/, $arguments) {
 | 
			
		||||
        $self->{pbot}->{logger}->log("$nick!$user\@$host made me part $channel\n");
 | 
			
		||||
        $self->{pbot}->{chanops}->part_channel($channel);
 | 
			
		||||
        $self->part($channel);
 | 
			
		||||
    }
 | 
			
		||||
    return "/msg $nick Parting $arguments";
 | 
			
		||||
}
 | 
			
		||||
@ -81,17 +81,11 @@ sub remove {
 | 
			
		||||
    my ($self, $from, $nick, $user, $host, $arguments) = @_;
 | 
			
		||||
    return "Usage: chanrem <channel>" if not defined $arguments or not length $arguments;
 | 
			
		||||
 | 
			
		||||
    # clear unban timeouts
 | 
			
		||||
    if ($self->{pbot}->{chanops}->{unban_timeout}->exists($arguments)) {
 | 
			
		||||
        $self->{pbot}->{chanops}->{unban_timeout}->remove($arguments);
 | 
			
		||||
        $self->{pbot}->{timer}->dequeue_event("unban_timeout $arguments .*");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    # clear unmute timeouts
 | 
			
		||||
    if ($self->{pbot}->{chanops}->{unmute_timeout}->exists($arguments)) {
 | 
			
		||||
        $self->{pbot}->{chanops}->{unmute_timeout}->remove($arguments);
 | 
			
		||||
        $self->{pbot}->{timer}->dequeue_event("unmute_timeout $arguments .*");
 | 
			
		||||
    }
 | 
			
		||||
    # clear banlists
 | 
			
		||||
    $self->{pbot}->{banlist}->remove($arguments);
 | 
			
		||||
    $self->{pbot}->{quietlist}->remove($arguments);
 | 
			
		||||
    $self->{pbot}->{timer}->dequeue_event("unban $arguments .*");
 | 
			
		||||
    $self->{pbot}->{timer}->dequeue_event("unmute $arguments .*");
 | 
			
		||||
 | 
			
		||||
    # TODO: ignores, etc?
 | 
			
		||||
    return $self->{channels}->remove($arguments);
 | 
			
		||||
@ -112,21 +106,51 @@ sub list {
 | 
			
		||||
    return $result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub join {
 | 
			
		||||
    my ($self, $channels) = @_;
 | 
			
		||||
 | 
			
		||||
    $self->{pbot}->{conn}->join($channels);
 | 
			
		||||
 | 
			
		||||
    foreach my $channel (split /,/, $channels) {
 | 
			
		||||
        $channel = lc $channel;
 | 
			
		||||
        $self->{pbot}->{event_dispatcher}->dispatch_event('pbot.join', {channel => $channel});
 | 
			
		||||
 | 
			
		||||
        delete $self->{pbot}->{chanops}->{is_opped}->{$channel};
 | 
			
		||||
        delete $self->{pbot}->{chanops}->{op_requested}->{$channel};
 | 
			
		||||
 | 
			
		||||
        if ($self->{channels}->exists($channel) and $self->{channels}->get_data($channel, 'permop')) {
 | 
			
		||||
            $self->gain_ops($channel);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $self->{pbot}->{conn}->mode($channel);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub part {
 | 
			
		||||
    my ($self, $channel) = @_;
 | 
			
		||||
    $channel = lc $channel;
 | 
			
		||||
    $self->{pbot}->{event_dispatcher}->dispatch_event('pbot.part', {channel => $channel});
 | 
			
		||||
    $self->{pbot}->{conn}->part($channel);
 | 
			
		||||
    delete $self->{pbot}->{chanops}->{is_opped}->{$channel};
 | 
			
		||||
    delete $self->{pbot}->{chanops}->{op_requested}->{$channel};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub autojoin {
 | 
			
		||||
    my ($self) = @_;
 | 
			
		||||
    return if $self->{pbot}->{joined_channels};
 | 
			
		||||
    my $channels;
 | 
			
		||||
    foreach my $channel ($self->{channels}->get_keys) {
 | 
			
		||||
        if ($self->{channels}->get_data($channel, 'enabled')) { $channels .= $self->{channels}->get_key_name($channel) . ','; }
 | 
			
		||||
        if ($self->{channels}->get_data($channel, 'enabled')) {
 | 
			
		||||
            $channels .= $self->{channels}->get_key_name($channel) . ',';
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    $self->{pbot}->{logger}->log("Joining channels: $channels\n");
 | 
			
		||||
    $self->{pbot}->{chanops}->join_channel($channels);
 | 
			
		||||
    $self->join($channels);
 | 
			
		||||
    $self->{pbot}->{joined_channels} = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub is_active {
 | 
			
		||||
    my ($self, $channel) = @_;
 | 
			
		||||
 | 
			
		||||
    # returns undef if channel doesn't exist; otherwise, the value of 'enabled'
 | 
			
		||||
    return $self->{channels}->get_data($channel, 'enabled');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -203,7 +203,7 @@ sub on_action {
 | 
			
		||||
 | 
			
		||||
sub on_mode {
 | 
			
		||||
    my ($self, $event_type, $event) = @_;
 | 
			
		||||
    my ($nick, $user,       $host)  = ($event->{event}->nick, $event->{event}->user, $event->{event}->host);
 | 
			
		||||
    my ($nick, $user, $host) = ($event->{event}->nick, $event->{event}->user, $event->{event}->host);
 | 
			
		||||
    my $mode_string = $event->{event}->{args}[0];
 | 
			
		||||
    my $channel     = $event->{event}->{to}[0];
 | 
			
		||||
    $channel = lc $channel;
 | 
			
		||||
@ -228,15 +228,18 @@ sub on_mode {
 | 
			
		||||
 | 
			
		||||
        $self->{pbot}->{logger}->log("Mode $channel [$mode" . (length $target ? " $target" : '') . "] by $nick!$user\@$host\n");
 | 
			
		||||
 | 
			
		||||
        if ($mode eq "-b" or $mode eq "+b" or $mode eq "-q" or $mode eq "+q") { $self->{pbot}->{bantracker}->track_mode("$nick!$user\@$host", $mode, $target, $channel); }
 | 
			
		||||
        $self->{pbot}->{banlist}->track_mode("$nick!$user\@$host", $channel, $mode, $target);
 | 
			
		||||
        $self->{pbot}->{chanops}->track_mode("$nick!$user\@$host", $channel, $mode, $target);
 | 
			
		||||
 | 
			
		||||
        if (defined $target and length $target) {
 | 
			
		||||
            # mode set on user
 | 
			
		||||
            my $message_account = $self->{pbot}->{messagehistory}->get_message_account($nick, $user, $host);
 | 
			
		||||
            $self->{pbot}->{messagehistory}->add_message($message_account, "$nick!$user\@$host", $channel, "MODE $mode $target", $self->{pbot}->{messagehistory}->{MSG_CHAT});
 | 
			
		||||
 | 
			
		||||
            if ($modifier eq '-') { $self->{pbot}->{nicklist}->delete_meta($channel, $target, "+$mode_char"); }
 | 
			
		||||
            else                  { $self->{pbot}->{nicklist}->set_meta($channel, $target, $mode, 1); }
 | 
			
		||||
        } else {
 | 
			
		||||
            # mode set on channel
 | 
			
		||||
            my $modes = $self->{pbot}->{channels}->get_meta($channel, 'MODE');
 | 
			
		||||
            if (defined $modes) {
 | 
			
		||||
                if ($modifier eq '+') {
 | 
			
		||||
@ -248,78 +251,8 @@ sub on_mode {
 | 
			
		||||
                $self->{pbot}->{channels}->{channels}->set($channel, 'MODE', $modes, 1);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (defined $target && $target eq $event->{conn}->nick) {    # bot targeted
 | 
			
		||||
            if ($mode eq "+o") {
 | 
			
		||||
                $self->{pbot}->{logger}->log("$nick opped me in $channel\n");
 | 
			
		||||
                my $timeout = $self->{pbot}->{registry}->get_value($channel, 'deop_timeout') // $self->{pbot}->{registry}->get_value('general', 'deop_timeout');
 | 
			
		||||
                $self->{pbot}->{chanops}->{is_opped}->{$channel}{timeout} = gettimeofday + $timeout;
 | 
			
		||||
                delete $self->{pbot}->{chanops}->{op_requested}->{$channel};
 | 
			
		||||
                $self->{pbot}->{chanops}->perform_op_commands($channel);
 | 
			
		||||
            } elsif ($mode eq "-o") {
 | 
			
		||||
                $self->{pbot}->{logger}->log("$nick removed my ops in $channel\n");
 | 
			
		||||
                delete $self->{pbot}->{chanops}->{is_opped}->{$channel};
 | 
			
		||||
            } elsif ($mode eq "+b") {
 | 
			
		||||
                $self->{pbot}->{logger}->log("Got banned in $channel, attempting unban.");
 | 
			
		||||
                $event->{conn}->privmsg("chanserv", "unban $channel");
 | 
			
		||||
            }
 | 
			
		||||
        } else {    # bot not targeted
 | 
			
		||||
            if ($mode eq "+b") {
 | 
			
		||||
                if ($nick eq "ChanServ" or $target =~ m/##fix_your_connection$/i) {
 | 
			
		||||
                    if ($self->{pbot}->{chanops}->can_gain_ops($channel)) {
 | 
			
		||||
                        if ($self->{pbot}->{chanops}->{unban_timeout}->exists($channel, $target)) {
 | 
			
		||||
                            $self->{pbot}->{chanops}->{unban_timeout}->set($channel, $target, 'timeout', gettimeofday + $self->{pbot}->{registry}->get_value('bantracker', 'chanserv_ban_timeout'));
 | 
			
		||||
                            $self->{pbot}->{timer}->update_interval("unban_timeout $channel $target", $self->{pbot}->{registry}->get_value('bantracker', 'chanserv_ban_timeout'));
 | 
			
		||||
                        } else {
 | 
			
		||||
                            my $data = {
 | 
			
		||||
                                reason  => 'Temp ban for banned-by-ChanServ or mask is *!*@*##fix_your_connection',
 | 
			
		||||
                                owner   => $self->{pbot}->{registry}->get_value('irc', 'botnick'),
 | 
			
		||||
                                timeout => gettimeofday + $self->{pbot}->{registry}->get_value('bantracker', 'chanserv_ban_timeout'),
 | 
			
		||||
                            };
 | 
			
		||||
                            $self->{pbot}->{chanops}->{unban_timeout}->add($channel, $target, $data);
 | 
			
		||||
                            $self->{pbot}->{chanops}->enqueue_unban_timeout($channel, $target, $self->{pbot}->{registry}->get_value('bantracker', 'chanserv_ban_timeout'));
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                } elsif ($target =~ m/^\*!\*@/ or $target =~ m/^\*!.*\@gateway\/web/i) {
 | 
			
		||||
                    my $timeout = 60 * 60 * 24 * 7;
 | 
			
		||||
 | 
			
		||||
                    if ($target =~ m/\// and $target !~ m/\@gateway/) {
 | 
			
		||||
                        $timeout = 0;    # permanent bans for cloaks that aren't gateway
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if ($timeout && $self->{pbot}->{chanops}->can_gain_ops($channel)) {
 | 
			
		||||
                        if (not $self->{pbot}->{chanops}->{unban_timeout}->exists($channel, $target)) {
 | 
			
		||||
                            $self->{pbot}->{logger}->log("Temp ban for $target in $channel.\n");
 | 
			
		||||
                            my $data = {
 | 
			
		||||
                                reason  => 'Temp ban for *!*@... banmask',
 | 
			
		||||
                                timeout => gettimeofday + $timeout,
 | 
			
		||||
                                owner   => $self->{pbot}->{registry}->get_value('irc', 'botnick'),
 | 
			
		||||
                            };
 | 
			
		||||
                            $self->{pbot}->{chanops}->{unban_timeout}->add($channel, $target, $data);
 | 
			
		||||
                            $self->{pbot}->{chanops}->enqueue_unban_timeout($channel, $target, $timeout);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            } elsif ($mode eq "+q") {
 | 
			
		||||
                if ($nick ne $event->{conn}->nick) {    # bot muted
 | 
			
		||||
                    if ($self->{pbot}->{chanops}->can_gain_ops($channel)) {
 | 
			
		||||
                        if ($self->{pbot}->{chanops}->{unmute_timeout}->exists($channel, $target)) {
 | 
			
		||||
                            $self->{pbot}->{chanops}->{unmute_timeout}->set($channel, $target, 'timeout', gettimeofday + $self->{pbot}->{registry}->get_value('bantracker', 'chanserv_ban_timeout'));
 | 
			
		||||
                            $self->{pbot}->{timer}->update_interval("unmute_timeout $channel $target", $self->{pbot}->{registry}->get_value('bantracker', 'chanserv_ban_timeout'));
 | 
			
		||||
                        } else {
 | 
			
		||||
                            my $data = {
 | 
			
		||||
                                reason  => 'Temp mute',
 | 
			
		||||
                                owner   => $self->{pbot}->{registry}->get_value('irc', 'botnick'),
 | 
			
		||||
                                timeout => gettimeofday + $self->{pbot}->{registry}->get_value('bantracker', 'mute_timeout'),
 | 
			
		||||
                            };
 | 
			
		||||
                            $self->{pbot}->{chanops}->{unmute_timeout}->add($channel, $target, $data);
 | 
			
		||||
                            $self->{pbot}->{chanops}->enqueue_unmute_timeout($channel, $target, $self->{pbot}->{registry}->get_value('bantracker', 'mute_timeout'));
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -51,12 +51,12 @@ sub process_line {
 | 
			
		||||
        my $chanmodes = $self->{pbot}->{channels}->get_meta($from, 'MODE');
 | 
			
		||||
        if (defined $chanmodes and $chanmodes =~ m/z/) {
 | 
			
		||||
            $stuff->{'chan-z'} = 1;
 | 
			
		||||
            if (exists $self->{pbot}->{bantracker}->{banlist}->{$from}->{'+q'}->{'$~a'}) {
 | 
			
		||||
            if ($self->{pbot}->{banlist}->{quietlist}->exists($from, '$~a')) {
 | 
			
		||||
                my $nickserv = $self->{pbot}->{messagehistory}->{database}->get_current_nickserv_account($message_account);
 | 
			
		||||
                if (not defined $nickserv or not length $nickserv) { $stuff->{unidentified} = 1; }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if ($self->{pbot}->{bantracker}->is_banned($nick, $user, $host, $from)) { $stuff->{banned} = 1; }
 | 
			
		||||
            $stuff->{banned} = 1 if $self->{pbot}->{banlist}->is_banned($nick, $user, $host, $from);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										25
									
								
								PBot/PBot.pm
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								PBot/PBot.pm
									
									
									
									
									
								
							@ -29,7 +29,7 @@ use PBot::IRC;
 | 
			
		||||
use PBot::EventDispatcher;
 | 
			
		||||
use PBot::IRCHandlers;
 | 
			
		||||
use PBot::Channels;
 | 
			
		||||
use PBot::BanTracker;
 | 
			
		||||
use PBot::BanList;
 | 
			
		||||
use PBot::NickList;
 | 
			
		||||
use PBot::LagChecker;
 | 
			
		||||
use PBot::MessageHistory;
 | 
			
		||||
@ -231,7 +231,6 @@ sub initialize {
 | 
			
		||||
    $self->{select_handler}   = PBot::SelectHandler->new(pbot => $self, %conf);
 | 
			
		||||
    $self->{users}            = PBot::Users->new(pbot => $self, filename => "$data_dir/users", %conf);
 | 
			
		||||
    $self->{stdin_reader}     = PBot::StdinReader->new(pbot => $self, %conf);
 | 
			
		||||
    $self->{bantracker}       = PBot::BanTracker->new(pbot => $self, %conf);
 | 
			
		||||
    $self->{lagchecker}       = PBot::LagChecker->new(pbot => $self, %conf);
 | 
			
		||||
    $self->{messagehistory}   = PBot::MessageHistory->new(pbot => $self, filename => "$data_dir/message_history.sqlite3", %conf);
 | 
			
		||||
    $self->{antiflood}        = PBot::AntiFlood->new(pbot => $self, %conf);
 | 
			
		||||
@ -241,6 +240,7 @@ sub initialize {
 | 
			
		||||
    $self->{irc}              = PBot::IRC->new();
 | 
			
		||||
    $self->{channels}         = PBot::Channels->new(pbot => $self, filename => "$data_dir/channels", %conf);
 | 
			
		||||
    $self->{chanops}          = PBot::ChanOps->new(pbot => $self, %conf);
 | 
			
		||||
    $self->{banlist}          = PBot::BanList->new(pbot => $self, %conf);
 | 
			
		||||
    $self->{nicklist}         = PBot::NickList->new(pbot => $self, %conf);
 | 
			
		||||
    $self->{webpaste}         = PBot::WebPaste->new(pbot => $self, %conf);
 | 
			
		||||
    $self->{parsedate}        = PBot::Utils::ParseDate->new(pbot => $self, %conf);
 | 
			
		||||
@ -319,7 +319,6 @@ sub connect {
 | 
			
		||||
            'motdstart',
 | 
			
		||||
            'endofmotd',
 | 
			
		||||
            'away',
 | 
			
		||||
            'endofbanlist'
 | 
			
		||||
        ],
 | 
			
		||||
        sub { }
 | 
			
		||||
    );
 | 
			
		||||
@ -479,18 +478,14 @@ sub reload {
 | 
			
		||||
            return "Channels reloaded.";
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        'bantimeouts' => sub {
 | 
			
		||||
            $self->{timer}->dequeue_event('unban_timeout .*');
 | 
			
		||||
            $self->{chanops}->{unban_timeout}->load;
 | 
			
		||||
            $self->{chanops}->enqueue_unban_timeouts;
 | 
			
		||||
            return "Ban timeouts reloaded.";
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        'mutetimeouts' => sub {
 | 
			
		||||
            $self->{timer}->dequeue_event('unmute_timeout .*');
 | 
			
		||||
            $self->{chanops}->{unmute_timeout}->load;
 | 
			
		||||
            $self->{chanops}->enqueue_unmute_timeouts;
 | 
			
		||||
            return "Mute timeouts reloaded.";
 | 
			
		||||
        'banlist' => sub {
 | 
			
		||||
            $self->{timer}->dequeue_event('unban #.*');
 | 
			
		||||
            $self->{timer}->dequeue_event('unmute #.*');
 | 
			
		||||
            $self->{banlist}->{banlist}->load;
 | 
			
		||||
            $self->{banlist}->{quietlist}->load;
 | 
			
		||||
            $self->{chanops}->enqueue_timeouts($self->{banlist}->{banlist},   'b');
 | 
			
		||||
            $self->{chanops}->enqueue_timeouts($self->{banlist}->{quietlist}, 'q');
 | 
			
		||||
            return "Ban list reloaded.";
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        'registry' => sub {
 | 
			
		||||
 | 
			
		||||
@ -15,8 +15,9 @@ use feature 'unicode_strings';
 | 
			
		||||
 | 
			
		||||
sub initialize {
 | 
			
		||||
    my ($self, %conf) = @_;
 | 
			
		||||
    $self->{pbot}->{registry}
 | 
			
		||||
      ->add_default('text', 'antiaway', 'bad_nicks', $conf{bad_nicks} // '([[:punct:]](afk|brb|bbl|away|sleep|z+|work|gone|study|out|home|busy|off)[[:punct:]]*$|.+\[.*\]$)');
 | 
			
		||||
    $self->{pbot}->{registry}->add_default('text', 'antiaway', 'bad_nicks',
 | 
			
		||||
        $conf{bad_nicks} // '([[:punct:]](afk|brb|bbl|away|sleep|z+|work|gone|study|out|home|busy|off)[[:punct:]]*$|.+\[.*\]$)'
 | 
			
		||||
    );
 | 
			
		||||
    $self->{pbot}->{registry}->add_default('text', 'antiaway', 'bad_actions', $conf{bad_actions} // '^/me (is (away|gone)|.*auto.?away)');
 | 
			
		||||
    $self->{pbot}->{registry}->add_default('text', 'antiaway', 'kick_msg',    'http://sackheads.org/~bnaylor/spew/away_msgs.html');
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -35,14 +35,16 @@ sub unload {
 | 
			
		||||
 | 
			
		||||
sub on_kick {
 | 
			
		||||
    my ($self, $event_type, $event) = @_;
 | 
			
		||||
    my ($nick, $user, $host, $target, $channel, $reason) =
 | 
			
		||||
      ($event->{event}->nick, $event->{event}->user, $event->{event}->host, $event->{event}->to, $event->{event}->{args}[0], $event->{event}->{args}[1]);
 | 
			
		||||
    my ($nick, $user, $host) = ($event->{event}->nick, $event->{event}->user, $event->{event}->host);
 | 
			
		||||
    my ($target, $channel, $reason) = ($event->{event}->to, $event->{event}->{args}[0], $event->{event}->{args}[1]);
 | 
			
		||||
 | 
			
		||||
    $channel = lc $channel;
 | 
			
		||||
    return 0 if not $self->{pbot}->{chanops}->can_gain_ops($channel);
 | 
			
		||||
    return 0 if $reason eq '*BANG!*';                                   # roulette
 | 
			
		||||
 | 
			
		||||
    if (not exists $self->{kicks}->{$channel} or not exists $self->{kicks}->{$channel}->{$target}) { $self->{kicks}->{$channel}->{$target}->{rejoins} = 0; }
 | 
			
		||||
    if (not exists $self->{kicks}->{$channel} or not exists $self->{kicks}->{$channel}->{$target}) {
 | 
			
		||||
        $self->{kicks}->{$channel}->{$target}->{rejoins} = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $self->{kicks}->{$channel}->{$target}->{last_kick} = gettimeofday;
 | 
			
		||||
    return 0;
 | 
			
		||||
@ -65,12 +67,20 @@ sub on_join {
 | 
			
		||||
            my $duration = duration($timeout);
 | 
			
		||||
            $duration =~ s/s$//;    # hours -> hour, minutes -> minute
 | 
			
		||||
 | 
			
		||||
            $self->{pbot}->{chanops}->ban_user_timed($self->{pbot}->{registry}->get_value('irc', 'botnick'), 'autorejoining after kick', "*!$user\@$host", $channel, $timeout);
 | 
			
		||||
            $self->{pbot}->{banlist}->ban_user_timed(
 | 
			
		||||
                $channel,
 | 
			
		||||
                'b',
 | 
			
		||||
                "*!$user\@$host",
 | 
			
		||||
                $timeout,
 | 
			
		||||
                $self->{pbot}->{registry}->get_value('irc', 'botnick'),
 | 
			
		||||
                'autorejoining after kick',
 | 
			
		||||
            );
 | 
			
		||||
            $self->{pbot}->{chanops}->add_op_command($channel, "kick $channel $nick $duration ban for auto-rejoining after kick; use this time to think about why you were kicked");
 | 
			
		||||
            $self->{pbot}->{chanops}->gain_ops($channel);
 | 
			
		||||
            $self->{kicks}->{$channel}->{$nick}->{rejoins}++;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -69,7 +69,14 @@ sub check_flood {
 | 
			
		||||
 | 
			
		||||
    if (exists $self->{nicks}->{$channel} and @{$self->{nicks}->{$channel}} >= 10) {
 | 
			
		||||
        $self->{pbot}->{logger}->log("Nick spam flood detected in $channel\n");
 | 
			
		||||
        $self->{pbot}->{chanops}->mute_user_timed($self->{pbot}->{registry}->get_value('irc', 'botnick'), 'nick spam flooding', '$~a', $channel, 60 * 15);
 | 
			
		||||
        $self->{pbot}->{banlist}->ban_user_timed(
 | 
			
		||||
            $channel,
 | 
			
		||||
            'q',
 | 
			
		||||
            '$~a',
 | 
			
		||||
            60 * 15,
 | 
			
		||||
            $self->{pbot}->{registry}->get_value('irc', 'botnick'),
 | 
			
		||||
            'nick spam flooding',
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -79,9 +86,13 @@ sub clear_old_nicks {
 | 
			
		||||
    return if not exists $self->{nicks}->{$channel};
 | 
			
		||||
 | 
			
		||||
    while (1) {
 | 
			
		||||
        if   (@{$self->{nicks}->{$channel}} and $self->{nicks}->{$channel}->[0]->[0] <= $now - 15) { shift @{$self->{nicks}->{$channel}}; }
 | 
			
		||||
        else                                                                                       { last; }
 | 
			
		||||
        if   (@{$self->{nicks}->{$channel}} and $self->{nicks}->{$channel}->[0]->[0] <= $now - 15) {
 | 
			
		||||
            shift @{$self->{nicks}->{$channel}};
 | 
			
		||||
        } else {
 | 
			
		||||
            last;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    delete $self->{nicks}->{$channel} if not @{$self->{nicks}->{$channel}};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -59,7 +59,7 @@ sub on_public {
 | 
			
		||||
 | 
			
		||||
    # don't enforce anti-repeat for unreg spam
 | 
			
		||||
    my $chanmodes = $self->{pbot}->{channels}->get_meta($channel, 'MODE');
 | 
			
		||||
    if (defined $chanmodes and $chanmodes =~ m/z/ and exists $self->{pbot}->{bantracker}->{banlist}->{$channel}->{'+q'}->{'$~a'}) {
 | 
			
		||||
    if (defined $chanmodes and $chanmodes =~ m/z/ and $self->{pbot}->{banlist}->{quietlist}->exists($channel, '$~a')) {
 | 
			
		||||
        my $nickserv = $self->{pbot}->{messagehistory}->{database}->get_current_nickserv_account($account);
 | 
			
		||||
        return 0 if not defined $nickserv or not length $nickserv;
 | 
			
		||||
    }
 | 
			
		||||
@ -136,9 +136,9 @@ sub on_public {
 | 
			
		||||
                    $self->{pbot}->{chanops}->add_op_command($channel, "kick $channel $nick Stop repeating yourself");
 | 
			
		||||
                    $self->{pbot}->{chanops}->gain_ops($channel);
 | 
			
		||||
                }
 | 
			
		||||
                when (2) { $self->{pbot}->{chanops}->ban_user_timed($botnick, 'repeating messages', "*!*\@$host", $channel, 30); }
 | 
			
		||||
                when (3) { $self->{pbot}->{chanops}->ban_user_timed($botnick, 'repeating messages', "*!*\@$host", $channel, 60 * 5); }
 | 
			
		||||
                default  { $self->{pbot}->{chanops}->ban_user_timed($botnick, 'repeating messages', "*!*\@$host", $channel, 60 * 60); }
 | 
			
		||||
                when (2) { $self->{pbot}->{banlist}->ban_user_timed($channel, 'b', "*!*\@$host", 30,      $botnick, 'repeating messages'); }
 | 
			
		||||
                when (3) { $self->{pbot}->{banlist}->ban_user_timed($channel, 'b', "*!*\@$host", 60 * 5,  $botnick, 'repeating messages'); }
 | 
			
		||||
                default  { $self->{pbot}->{banlist}->ban_user_timed($channel, 'b', "*!*\@$host", 60 * 60, $botnick, 'repeating messages'); }
 | 
			
		||||
            }
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -51,15 +51,25 @@ sub on_public {
 | 
			
		||||
            $self->{pbot}->{logger}->log("$nick!$user\@$host is a twit. ($self->{offenses}->{$channel}->{$nick}->{offenses} offenses) $channel: $msg\n");
 | 
			
		||||
 | 
			
		||||
            given ($self->{offenses}->{$channel}->{$nick}->{offenses}) {
 | 
			
		||||
                when (1) { $event->{conn}->privmsg($nick, "Please do not use \@nick to address people. Drop the @ symbol; it's not necessary and it's ugly."); }
 | 
			
		||||
                when (2) {
 | 
			
		||||
                    $event->{conn}
 | 
			
		||||
                      ->privmsg($nick, "Please do not use \@nick to address people. Drop the @ symbol; it's not necessary and it's ugly. Doing this again will result in a temporary ban.");
 | 
			
		||||
                when (1) {
 | 
			
		||||
                    $event->{conn}->privmsg($nick, "Please do not use \@nick to address people. Drop the @ symbol; it's not necessary and it's ugly.");
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                when (2) {
 | 
			
		||||
                    $event->{conn}->privmsg($nick, "Please do not use \@nick to address people. Drop the @ symbol; it's not necessary and it's ugly. Doing this again will result in a temporary ban.");
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                default {
 | 
			
		||||
                    my $offenses = $self->{offenses}->{$channel}->{$nick}->{offenses} - 2;
 | 
			
		||||
                    my $length   = 60 * ($offenses * $offenses + 1);
 | 
			
		||||
                    $self->{pbot}->{chanops}->ban_user_timed($self->{pbot}->{registry}->get_value('irc', 'botnick'), 'using @nick too much', "*!*\@$host", $channel, $length);
 | 
			
		||||
                    $self->{pbot}->{banlist}->ban_user_timed(
 | 
			
		||||
                        $channel,
 | 
			
		||||
                        'b',
 | 
			
		||||
                        "*!*\@$host",
 | 
			
		||||
                        $length,
 | 
			
		||||
                        $self->{pbot}->{registry}->get_value('irc', 'botnick'),
 | 
			
		||||
                        'using @nick too much',
 | 
			
		||||
                    );
 | 
			
		||||
                    $self->{pbot}->{chanops}->gain_ops($channel);
 | 
			
		||||
 | 
			
		||||
                    $self->{pbot}->{timer}->enqueue_event(sub {
 | 
			
		||||
@ -69,7 +79,7 @@ sub on_public {
 | 
			
		||||
                                delete $self->{offenses}->{$channel} if not keys %{$self->{offenses}->{$channel}};
 | 
			
		||||
                                $event->{repeating} = 0;
 | 
			
		||||
                            }
 | 
			
		||||
                        }, 60 * 60 * 24 * 2, "antitwitter offenses-- $channel $nick", 1
 | 
			
		||||
                        }, 60 * 60 * 24 * 2, "antitwitter $channel $nick", 1
 | 
			
		||||
                    );
 | 
			
		||||
 | 
			
		||||
                    $length = duration $length;
 | 
			
		||||
 | 
			
		||||
@ -30,7 +30,7 @@ sub on_public {
 | 
			
		||||
    return 0 if not length $msg;
 | 
			
		||||
 | 
			
		||||
    # exit if channel hasn't muted $~a
 | 
			
		||||
    return 0 if not exists $self->{pbot}->{bantracker}->{banlist}->{$channel}->{'+q'}->{'$~a'};
 | 
			
		||||
    return 0 if not $self->{pbot}->{banlist}->{quietlist}->exists($channel, '$~a');
 | 
			
		||||
 | 
			
		||||
    # exit if channel isn't +z
 | 
			
		||||
    my $chanmodes = $self->{pbot}->{channels}->get_meta($channel, 'MODE');
 | 
			
		||||
@ -101,7 +101,7 @@ sub check_queue {
 | 
			
		||||
            # if nick is still present in channel, send the message
 | 
			
		||||
            if ($self->{pbot}->{nicklist}->is_present($channel, $nick)) {
 | 
			
		||||
                # ensure they're not banned (+z allows us to see +q/+b messages as normal ones)
 | 
			
		||||
                my $banned = $self->{pbot}->{bantracker}->is_banned($nick, $user, $host, $channel);
 | 
			
		||||
                my $banned = $self->{pbot}->{banlist}->is_banned($nick, $user, $host, $channel);
 | 
			
		||||
                $self->{pbot}->{logger}
 | 
			
		||||
                  ->log("[RelayUnreg] $nick!$user\@$host $banned->{mode} as $banned->{banmask} in $banned->{channel} by $banned->{owner}, not relaying unregistered message\n")
 | 
			
		||||
                  if $banned;
 | 
			
		||||
 | 
			
		||||
@ -50,8 +50,11 @@ sub help {
 | 
			
		||||
    my ($self, $stuff) = @_;
 | 
			
		||||
    my $command = $self->{pbot}->{interpreter}->shift_arg($stuff->{arglist}) // 'help';
 | 
			
		||||
 | 
			
		||||
    if   (exists $self->{commands}->{$command}) { return $self->{commands}->{$command}->{help}; }
 | 
			
		||||
    else                                        { return "No such mod command '$command'. I can't help you with that."; }
 | 
			
		||||
    if (exists $self->{commands}->{$command}) {
 | 
			
		||||
        return $self->{commands}->{$command}->{help};
 | 
			
		||||
    } else {
 | 
			
		||||
        return "No such mod command '$command'. I can't help you with that.";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub list {
 | 
			
		||||
@ -85,17 +88,17 @@ sub generic_command {
 | 
			
		||||
    return "Missing target. Usage: mod $command <nick>" if not defined $target;
 | 
			
		||||
 | 
			
		||||
    if ($command eq 'unban') {
 | 
			
		||||
        my $reason = $self->{pbot}->{chanops}->checkban($channel, $target);
 | 
			
		||||
        my $reason = $self->{pbot}->{banlist}->checkban($channel, 'b', $target);
 | 
			
		||||
        if ($reason =~ m/moderator ban/) {
 | 
			
		||||
            $self->{pbot}->{chanops}->unban_user($target, $channel, 1);
 | 
			
		||||
            $self->{pbot}->{chanops}->unban_user($channel, 'b', $target, 1);
 | 
			
		||||
            return "";
 | 
			
		||||
        } else {
 | 
			
		||||
            return "I don't think so. That ban was not set by a moderator.";
 | 
			
		||||
        }
 | 
			
		||||
    } elsif ($command eq 'unmute') {
 | 
			
		||||
        my $reason = $self->{pbot}->{chanops}->checkmute($channel, $target);
 | 
			
		||||
        my $reason = $self->{pbot}->{banlist}->checkban($channel, 'q', $target);
 | 
			
		||||
        if ($reason =~ m/moderator mute/) {
 | 
			
		||||
            $self->{pbot}->{chanops}->unmute_user($target, $channel, 1);
 | 
			
		||||
            $self->{pbot}->{banlist}->unban_user($channel, 'q', $target, 1);
 | 
			
		||||
            return "";
 | 
			
		||||
        } else {
 | 
			
		||||
            return "I don't think so. That mute was not set by a moderator.";
 | 
			
		||||
@ -120,14 +123,24 @@ sub generic_command {
 | 
			
		||||
        $self->{pbot}->{chanops}->add_op_command($channel, "kick $channel $target Have a nice day!");
 | 
			
		||||
        $self->{pbot}->{chanops}->gain_ops($channel);
 | 
			
		||||
    } elsif ($command eq 'ban') {
 | 
			
		||||
        $self->{pbot}->{chanops}->ban_user_timed(
 | 
			
		||||
        $self->{pbot}->{banlist}->ban_user_timed(
 | 
			
		||||
            $channel,
 | 
			
		||||
            'b',
 | 
			
		||||
            $target,
 | 
			
		||||
            3600 * 24,
 | 
			
		||||
            "$stuff->{nick}!$stuff->{user}\@$stuff->{host}",
 | 
			
		||||
            "doing something naughty (moderator ban)", $target, $channel, 3600 * 24, 1
 | 
			
		||||
            "doing something naughty (moderator ban)",
 | 
			
		||||
            1
 | 
			
		||||
        );
 | 
			
		||||
    } elsif ($command eq 'mute') {
 | 
			
		||||
        $self->{pbot}->{chanops}->mute_user_timed(
 | 
			
		||||
        $self->{pbot}->{banlist}->ban_user_timed(
 | 
			
		||||
            $channel,
 | 
			
		||||
            'q',
 | 
			
		||||
            $target,
 | 
			
		||||
            3600 * 24,
 | 
			
		||||
            "$stuff->{nick}!$stuff->{user}\@$stuff->{host}",
 | 
			
		||||
            "doing something naughty (moderator mute)", $target, $channel, 3600 * 24, 1
 | 
			
		||||
            "doing something naughty (moderator mute)",
 | 
			
		||||
            1
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
    return "";
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user