mirror of
https://github.com/pragma-/pbot.git
synced 2024-11-22 11:59:43 +01:00
Finalize BanList refactor; add updater
This commit is contained in:
parent
013fa6b51c
commit
f347d1798b
@ -397,7 +397,7 @@ sub check_flood {
|
||||
} elsif ($mode == $self->{pbot}->{messagehistory}->{MSG_CHAT}) {
|
||||
if ($chan =~ /^#/) { #channel flood (opposed to private message or otherwise)
|
||||
# don't increment offenses again if already banned
|
||||
if ($self->{pbot}->{chanops}->has_ban_timeout($chan, "*!$user\@" . $self->address_to_mask($host))) {
|
||||
if ($self->{pbot}->{banlist}->has_ban_timeout($chan, "*!$user\@" . $self->address_to_mask($host))) {
|
||||
$self->{pbot}->{logger}->log("$nick $chan flood offense disregarded due to existing ban\n");
|
||||
next;
|
||||
}
|
||||
@ -496,7 +496,7 @@ sub check_flood {
|
||||
$chan_data->{enter_abuses}++;
|
||||
if ($chan_data->{enter_abuses} >= $enter_abuse_max_offenses) {
|
||||
if ($self->{pbot}->{registry}->get_value('antiflood', 'enforce')) {
|
||||
if ($self->{pbot}->{chanops}->has_ban_timeout($chan, "*!$user\@" . $self->address_to_mask($host))) {
|
||||
if ($self->{pbot}->{banlist}->has_ban_timeout($chan, "*!$user\@" . $self->address_to_mask($host))) {
|
||||
$self->{pbot}->{logger}->log("$nick $chan enter abuse offense disregarded due to existing ban\n");
|
||||
next;
|
||||
}
|
||||
@ -594,13 +594,13 @@ sub unbanme {
|
||||
foreach my $baninfo (@$baninfos) {
|
||||
my $u = $self->{pbot}->{users}->loggedin($baninfo->{channel}, "$nick!$user\@$host");
|
||||
my $whitelisted = $self->{pbot}->{capabilities}->userhas($u, 'is-whitelisted');
|
||||
if ($self->ban_exempted($baninfo->{channel}, $baninfo->{banmask}) || $whitelisted) {
|
||||
$self->{pbot}->{logger}->log("anti-flood: [unbanme] $anick!$auser\@$ahost banned as $baninfo->{banmask} in $baninfo->{channel}, but allowed through whitelist\n");
|
||||
if ($self->ban_exempted($baninfo->{channel}, $baninfo->{mask}) || $whitelisted) {
|
||||
$self->{pbot}->{logger}->log("anti-flood: [unbanme] $anick!$auser\@$ahost 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("anti-flood: [unbanme] $anick!$auser\@$ahost $mode as $baninfo->{banmask} in $baninfo->{channel} by $baninfo->{owner}, unbanme rejected\n");
|
||||
return "/msg $nick You have been $mode as $baninfo->{banmask} by $baninfo->{owner}, unbanme will not work until it is removed.";
|
||||
$self->{pbot}->{logger}->log("anti-flood: [unbanme] $anick!$auser\@$ahost $mode as $baninfo->{mask} in $baninfo->{channel} by $baninfo->{owner}, unbanme rejected\n");
|
||||
return "/msg $nick You have been $mode as $baninfo->{mask} by $baninfo->{owner}, unbanme will not work until it is removed.";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -803,7 +803,7 @@ sub check_bans {
|
||||
}
|
||||
|
||||
my $baninfo = {};
|
||||
$baninfo->{banmask} = $alias;
|
||||
$baninfo->{mask} = $alias;
|
||||
$baninfo->{channel} = $channel;
|
||||
$baninfo->{owner} = 'blacklist';
|
||||
$baninfo->{when} = 0;
|
||||
@ -821,7 +821,7 @@ sub check_bans {
|
||||
foreach my $baninfo (@$baninfos) {
|
||||
if (time - $baninfo->{when} < 5) {
|
||||
$self->{pbot}->{logger}
|
||||
->log("anti-flood: [check-bans] $mask [$alias] evaded $baninfo->{banmask} in $baninfo->{channel}, but within 5 seconds of establishing ban; giving another chance\n");
|
||||
->log("anti-flood: [check-bans] $mask [$alias] evaded $baninfo->{mask} in $baninfo->{channel}, but within 5 seconds of establishing ban; giving another chance\n");
|
||||
my $channel_data = $self->{pbot}->{messagehistory}->{database}->get_channel_data($message_account, $channel, 'validated');
|
||||
if ($channel_data->{validated} & $self->{NICKSERV_VALIDATED}) {
|
||||
$channel_data->{validated} &= ~$self->{NICKSERV_VALIDATED};
|
||||
@ -833,18 +833,18 @@ sub check_bans {
|
||||
|
||||
my $u = $self->{pbot}->{users}->loggedin($baninfo->{channel}, $mask);
|
||||
my $whitelisted = $self->{pbot}->{capabilities}->userhas($u, 'is-whitelisted');
|
||||
if ($self->ban_exempted($baninfo->{channel}, $baninfo->{banmask}) || $whitelisted) {
|
||||
#$self->{pbot}->{logger}->log("anti-flood: [check-bans] $mask [$alias] evaded $baninfo->{banmask} in $baninfo->{channel}, but allowed through whitelist\n");
|
||||
if ($self->ban_exempted($baninfo->{channel}, $baninfo->{mask}) || $whitelisted) {
|
||||
#$self->{pbot}->{logger}->log("anti-flood: [check-bans] $mask [$alias] evaded $baninfo->{mask} in $baninfo->{channel}, but allowed through whitelist\n");
|
||||
next;
|
||||
}
|
||||
|
||||
# special case for twkm clone bans
|
||||
if ($baninfo->{banmask} =~ m/\?\*!\*@\*$/) {
|
||||
$self->{pbot}->{logger}->log("anti-flood: [check-bans] $mask [$alias] evaded $baninfo->{banmask} in $baninfo->{channel}, but disregarded due to clone ban\n");
|
||||
if ($baninfo->{mask} =~ m/\?\*!\*@\*$/) {
|
||||
$self->{pbot}->{logger}->log("anti-flood: [check-bans] $mask [$alias] evaded $baninfo->{mask} in $baninfo->{channel}, but disregarded due to clone ban\n");
|
||||
next;
|
||||
}
|
||||
|
||||
my $banmask_regex = quotemeta $baninfo->{banmask};
|
||||
my $banmask_regex = quotemeta $baninfo->{mask};
|
||||
$banmask_regex =~ s/\\\*/.*/g;
|
||||
$banmask_regex =~ s/\\\?/./g;
|
||||
|
||||
@ -853,7 +853,7 @@ sub check_bans {
|
||||
next;
|
||||
}
|
||||
|
||||
if (defined $nickserv and $baninfo->{type} eq '+q' and $baninfo->{banmask} =~ /^\$a:(.*)/ and lc $1 eq $nickserv and $nickserv eq $current_nickserv_account) {
|
||||
if (defined $nickserv and $baninfo->{type} eq '+q' and $baninfo->{mask} =~ /^\$a:(.*)/ and lc $1 eq $nickserv and $nickserv eq $current_nickserv_account) {
|
||||
$self->{pbot}->{logger}->log("anti-flood: [check-bans] Hostmask ($mask) matches quiet on account ($nickserv), disregarding\n");
|
||||
next;
|
||||
}
|
||||
@ -861,7 +861,7 @@ sub check_bans {
|
||||
if (not defined $bans) { $bans = []; }
|
||||
|
||||
$self->{pbot}->{logger}
|
||||
->log("anti-flood: [check-bans] Hostmask ($mask [$alias" . (defined $nickserv ? "/$nickserv" : "") . "]) matches $baninfo->{type} $baninfo->{banmask}, adding ban\n");
|
||||
->log("anti-flood: [check-bans] Hostmask ($mask [$alias" . (defined $nickserv ? "/$nickserv" : "") . "]) matches $baninfo->{type} $baninfo->{mask}, adding ban\n");
|
||||
push @$bans, $baninfo;
|
||||
goto GOT_BAN;
|
||||
}
|
||||
@ -877,7 +877,7 @@ sub check_bans {
|
||||
my ($user, $host) = $mask =~ m/[^!]+!([^@]+)@(.*)/;
|
||||
if ($host =~ m{^([^/]+)/.+} and $1 ne 'gateway' and $1 ne 'nat') { $banmask = "*!*\@$host"; }
|
||||
elsif ( $current_nickserv_account
|
||||
and $baninfo->{banmask} !~ m/^\$a:/i
|
||||
and $baninfo->{mask} !~ m/^\$a:/i
|
||||
and not $self->{pbot}->{banlist}->{banlist}->exists($baninfo->{channel}, "\$a:$current_nickserv_account"))
|
||||
{
|
||||
$banmask = "\$a:$current_nickserv_account";
|
||||
@ -890,10 +890,10 @@ sub check_bans {
|
||||
}
|
||||
}
|
||||
|
||||
$self->{pbot}->{logger}->log("anti-flood: [check-bans] $mask evaded $baninfo->{banmask} banned in $baninfo->{channel} by $baninfo->{owner}, banning $banmask\n");
|
||||
$self->{pbot}->{logger}->log("anti-flood: [check-bans] $mask evaded $baninfo->{mask} banned in $baninfo->{channel} by $baninfo->{owner}, banning $banmask\n");
|
||||
my ($bannick) = $mask =~ m/^([^!]+)/;
|
||||
if ($self->{pbot}->{registry}->get_value('antiflood', 'enforce')) {
|
||||
if ($self->{pbot}->{chanops}->has_ban_timeout($baninfo->{channel}, $banmask)) {
|
||||
if ($self->{pbot}->{banlist}->has_ban_timeout($baninfo->{channel}, $banmask)) {
|
||||
$self->{pbot}->{logger}->log("anti-flood: [check-bans] $banmask already banned in $channel, disregarding\n");
|
||||
return;
|
||||
}
|
||||
@ -915,7 +915,7 @@ sub check_bans {
|
||||
else {
|
||||
my $owner = $baninfo->{owner};
|
||||
$owner =~ s/!.*$//;
|
||||
$self->{pbot}->{chanops}->add_op_command($baninfo->{channel}, "kick $baninfo->{channel} $bannick Evaded $baninfo->{banmask} set by $owner");
|
||||
$self->{pbot}->{chanops}->add_op_command($baninfo->{channel}, "kick $baninfo->{channel} $bannick Evaded $baninfo->{mask} set by $owner");
|
||||
}
|
||||
$self->{pbot}->{banlist}->ban_user_timed(
|
||||
$banmask, $baninfo->{channel},
|
||||
|
@ -75,7 +75,7 @@ sub banlist_cmd {
|
||||
|
||||
if ($self->{banlist}->exists($arguments)) {
|
||||
my $count = $self->{banlist}->get_keys($arguments);
|
||||
$result .= "$count bans:\n";
|
||||
$result .= "$count ban" . ($count == 1 ? '' : 's') . ":\n";
|
||||
foreach my $mask ($self->{banlist}->get_keys($arguments)) {
|
||||
my $data = $self->{banlist}->get_data($arguments, $mask);
|
||||
$result .= " $mask banned ";
|
||||
@ -100,7 +100,7 @@ sub banlist_cmd {
|
||||
|
||||
if ($self->{quietlist}->exists($arguments)) {
|
||||
my $count = $self->{quietlist}->get_keys($arguments);
|
||||
$result .= "$count mutes:\n";
|
||||
$result .= "$count mute" . ($count == 1 ? '' : 's') . ":\n";
|
||||
foreach my $mask ($self->{quietlist}->get_keys($arguments)) {
|
||||
my $data = $self->{quietlist}->get_data($arguments, $mask);
|
||||
$result .= " $mask muted ";
|
||||
@ -120,9 +120,10 @@ sub banlist_cmd {
|
||||
$result .= ";\n";
|
||||
}
|
||||
} else {
|
||||
$result .= "quiets: none;\n";
|
||||
$result .= "quiets: none\n";
|
||||
}
|
||||
|
||||
$result =~ s/ ;/;/g;
|
||||
return $result;
|
||||
}
|
||||
|
||||
@ -166,7 +167,7 @@ sub on_banlist_entry {
|
||||
my $timestamp = $event->{event}->{args}[4];
|
||||
|
||||
my $ago = concise ago(gettimeofday - $timestamp);
|
||||
$self->{pbot}->{logger}->log("banlist: [banlist entry] $channel: $target banned by $source $ago.\n");
|
||||
$self->{pbot}->{logger}->log("Ban List: [banlist entry] $channel: $target banned by $source $ago.\n");
|
||||
$self->{temp_banlist}->{$channel}->{'+b'}->{$target} = [$source, $timestamp];
|
||||
return 0;
|
||||
}
|
||||
@ -180,7 +181,7 @@ sub on_quietlist_entry {
|
||||
my $timestamp = $event->{event}->{args}[5];
|
||||
|
||||
my $ago = concise ago(gettimeofday - $timestamp);
|
||||
$self->{pbot}->{logger}->log("banlist: [quietlist entry] $channel: $target quieted by $source $ago.\n");
|
||||
$self->{pbot}->{logger}->log("Ban List: [quietlist entry] $channel: $target quieted by $source $ago.\n");
|
||||
$self->{temp_banlist}->{$channel}->{'+q'}->{$target} = [$source, $timestamp];
|
||||
return 0;
|
||||
}
|
||||
@ -189,7 +190,7 @@ 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");
|
||||
$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)) {
|
||||
@ -226,7 +227,8 @@ sub compare_banlist {
|
||||
$self->{banlist}->add($channel, $mask, $data, 1);
|
||||
}
|
||||
|
||||
$self->{banlist}->save;
|
||||
$self->{banlist}->save if keys %{$self->{temp_banlist}->{$channel}->{'+b'}};
|
||||
delete $self->{temp_banlist}->{$channel}->{'+b'};
|
||||
}
|
||||
|
||||
sub compare_quietlist {
|
||||
@ -253,7 +255,8 @@ sub compare_quietlist {
|
||||
$self->{quietlist}->add($channel, $mask, $data, 1);
|
||||
}
|
||||
|
||||
$self->{quietlist}->save;
|
||||
$self->{quietlist}->save if keys %{$self->{temp_banlist}->{$channel}->{'+q'}};
|
||||
delete $self->{temp_banlist}->{$channel}->{'+q'};
|
||||
}
|
||||
|
||||
sub track_mode {
|
||||
@ -265,7 +268,7 @@ sub track_mode {
|
||||
$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");
|
||||
$self->{pbot}->{logger}->log("Ban List: $mask " . ($mode eq '+b' ? 'banned' : 'quieted') . " by $source in $channel.\n");
|
||||
|
||||
my $data = {
|
||||
owner => $source,
|
||||
@ -280,7 +283,7 @@ sub track_mode {
|
||||
|
||||
$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");
|
||||
$self->{pbot}->{logger}->log("Ban List: $mask " . ($mode eq '-b' ? 'unbanned' : 'unquieted') . " by $source in $channel.\n");
|
||||
|
||||
if ($mode eq "-b") {
|
||||
$self->{banlist}->remove($channel, $mask);
|
||||
@ -323,7 +326,7 @@ sub track_mode {
|
||||
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',
|
||||
reason => 'Temp ban for *!*@host',
|
||||
timeout => gettimeofday + $timeout,
|
||||
owner => $self->{pbot}->{registry}->get_value('irc', 'botnick'),
|
||||
timestamp => gettimeofday,
|
||||
@ -383,14 +386,14 @@ sub unmode_user {
|
||||
my %unbanned;
|
||||
|
||||
if (not defined $bans) {
|
||||
push @$bans, { banmask => $mask, type => "+$mode" };
|
||||
push @$bans, { mask => $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});
|
||||
next if exists $unbanned{$ban->{mask}};
|
||||
$unbanned{$ban->{mask}} = 1;
|
||||
$self->add_to_unban_queue($channel, $mode, $ban->{mask});
|
||||
}
|
||||
|
||||
$self->flush_unban_queue if $immediately;
|
||||
@ -695,7 +698,8 @@ sub enqueue_timeouts {
|
||||
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;
|
||||
next if defined $timeout and $timeout <= 0;
|
||||
next if not defined $timeout;
|
||||
my $interval = $timeout - $now;
|
||||
$interval = 10 if $interval < 10;
|
||||
$self->enqueue_unban($channel, $mode, $mask, $interval);
|
||||
|
@ -19,8 +19,8 @@ use LWP::UserAgent;
|
||||
# These are set automatically by the misc/update_version script
|
||||
use constant {
|
||||
BUILD_NAME => "PBot",
|
||||
BUILD_REVISION => 3522,
|
||||
BUILD_DATE => "2020-04-24",
|
||||
BUILD_REVISION => 3536,
|
||||
BUILD_DATE => "2020-04-28",
|
||||
};
|
||||
|
||||
sub initialize {
|
||||
|
@ -103,7 +103,7 @@ sub check_queue {
|
||||
# ensure they're not banned (+z allows us to see +q/+b messages as normal ones)
|
||||
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")
|
||||
->log("[RelayUnreg] $nick!$user\@$host $banned->{mode} as $banned->{mask} in $banned->{channel} by $banned->{owner}, not relaying unregistered message\n")
|
||||
if $banned;
|
||||
$self->{pbot}->{conn}->privmsg($channel, "(unreg) <$nick> $msg") unless $banned;
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ sub generic_command {
|
||||
if ($command eq 'unban') {
|
||||
my $reason = $self->{pbot}->{banlist}->checkban($channel, 'b', $target);
|
||||
if ($reason =~ m/moderator ban/) {
|
||||
$self->{pbot}->{chanops}->unban_user($channel, 'b', $target, 1);
|
||||
$self->{pbot}->{banlist}->unban_user($channel, 'b', $target, 1);
|
||||
return "";
|
||||
} else {
|
||||
return "I don't think so. That ban was not set by a moderator.";
|
||||
|
4
data/banlist
vendored
4
data/banlist
vendored
@ -1,8 +1,8 @@
|
||||
{
|
||||
"$metadata$" : {
|
||||
"$metadata$" : {
|
||||
"update_version" : 3503,
|
||||
"name" : "Ban List"
|
||||
"name" : "Ban List",
|
||||
"update_version" : "3536"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
2
data/last_update
vendored
2
data/last_update
vendored
@ -1 +1 @@
|
||||
3512
|
||||
3536
|
||||
|
4
data/quietlist
vendored
4
data/quietlist
vendored
@ -1,8 +1,8 @@
|
||||
{
|
||||
"$metadata$" : {
|
||||
"$metadata$" : {
|
||||
"update_version" : 3503,
|
||||
"name" : "Quiet List"
|
||||
"name" : "Quiet List",
|
||||
"update_version" : "3536"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
6
data/registry
vendored
6
data/registry
vendored
@ -1,8 +1,8 @@
|
||||
{
|
||||
"$metadata$" : {
|
||||
"$metadata$" : {
|
||||
"update_version" : 3503,
|
||||
"name" : "Registry"
|
||||
"name" : "Registry",
|
||||
"update_version" : "3536"
|
||||
}
|
||||
},
|
||||
"antiaway" : {
|
||||
@ -123,7 +123,7 @@
|
||||
"value" : "900,1800,3600"
|
||||
}
|
||||
},
|
||||
"bantracker" : {
|
||||
"banlist" : {
|
||||
"chanserv_ban_timeout" : {
|
||||
"type" : "text",
|
||||
"value" : "604800"
|
||||
|
51
updates/3536_update_banlist.pl
Executable file
51
updates/3536_update_banlist.pl
Executable file
@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
# Convert unmute_timeouts and unban_timeouts to quietlist and banlist
|
||||
# Rename bantracker to banlist in registry
|
||||
|
||||
use warnings; use strict;
|
||||
|
||||
BEGIN {
|
||||
use File::Basename;
|
||||
my $location = -l __FILE__ ? dirname readlink __FILE__ : dirname __FILE__;
|
||||
unshift @INC, $location;
|
||||
}
|
||||
|
||||
use lib3512::DualIndexHashObject;
|
||||
use lib3503::PBot;
|
||||
|
||||
my ($data_dir, $version, $last_update) = @ARGV;
|
||||
|
||||
print "Updating ban list data... version: $version, last_update: $last_update, data_dir: $data_dir\n";
|
||||
|
||||
my $pbot = lib3503::PBot->new();
|
||||
|
||||
my $unmutes = lib3512::DualIndexHashObject->new(name => 'old unmute timeouts', filename => "$data_dir/unmute_timeouts", pbot => $pbot);
|
||||
$unmutes->load;
|
||||
|
||||
$unmutes->set('$metadata$', '$metadata$', 'name', 'Quiet List', 1);
|
||||
$unmutes->set('$metadata$', '$metadata$', 'update_version', '3536');
|
||||
|
||||
my $unbans = lib3512::DualIndexHashObject->new(name => 'old unban timeouts', filename => "$data_dir/unban_timeouts", pbot => $pbot);
|
||||
$unbans->load;
|
||||
|
||||
$unbans->set('$metadata$', '$metadata$', 'name', 'Ban List', 1);
|
||||
$unbans->set('$metadata$', '$metadata$', 'update_version', '3536');
|
||||
|
||||
use File::Copy;
|
||||
move("$data_dir/unmute_timeouts", "$data_dir/quietlist") or die "Failed to move unmute_timeouts -> quietlist: $!";
|
||||
move("$data_dir/unban_timeouts", "$data_dir/banlist") or die "Failed to move unban_timeouts -> banlist: $!";
|
||||
|
||||
my $registry = lib3512::DualIndexHashObject->new(name => 'Registry', filename => "$data_dir/registry", pbot => $pbot);
|
||||
$registry->load;
|
||||
|
||||
my $data = $registry->get_data('bantracker');
|
||||
$registry->remove('bantracker', undef, undef, 1);
|
||||
|
||||
foreach my $key (keys %{$data}) {
|
||||
$registry->add('banlist', $key, $data->{$key}, 1);
|
||||
}
|
||||
|
||||
$registry->set('$metadata$', '$metadata$', 'update_version', '3536');
|
||||
|
||||
exit 0;
|
Loading…
Reference in New Issue
Block a user