2020-02-01 03:29:52 +01:00
# 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 Plugins::RestrictedMod ;
# purpose: provides restricted moderation abilities to voiced users.
# They are allowed to ban/mute/kick only users that are not admins,
# whitelisted, or autoop/autovoice. This is useful for, e.g., IRCnet
# configurations where +v users are recognized as "semi-trusted" in
# order to provide assistance in combating heavy spam and drone traffic.
use warnings ;
use strict ;
use feature 'unicode_strings' ;
use Carp ( ) ;
2020-02-01 03:42:16 +01:00
use Storable qw/dclone/ ;
2020-02-01 03:29:52 +01:00
sub new {
Carp:: croak ( "Options to " . __FILE__ . " should be key/value pairs, not hash reference" ) if ref $ _ [ 1 ] eq 'HASH' ;
my ( $ class , % conf ) = @ _ ;
my $ self = bless { } , $ class ;
$ self - > initialize ( % conf ) ;
return $ self ;
}
sub initialize {
my ( $ self , % conf ) = @ _ ;
$ self - > { pbot } = $ conf { pbot } // Carp:: croak ( "Missing pbot reference to " . __FILE__ ) ;
$ self - > { pbot } - > { commands } - > register ( sub { $ self - > modcmd ( @ _ ) } , 'mod' , 0 ) ;
2020-02-01 07:51:31 +01:00
$ self - > { pbot } - > { commands } - > set_meta ( 'mod' , 'help' , 'Provides restricted moderation abilities to voiced users. They can kick/ban/etc only users that are not admins, whitelisted, voiced or opped.' ) ;
2020-02-01 03:29:52 +01:00
$ self - > { commands } = {
2020-02-01 07:03:50 +01:00
'help' = > { subref = > sub { $ self - > help ( @ _ ) } , help = > "Provides help about this command. Usage: mod help <mod command>; see also: mod help list" } ,
'list' = > { subref = > sub { $ self - > list ( @ _ ) } , help = > "Lists available mod commands. Usage: mod list" } ,
'kick' = > { subref = > sub { $ self - > kick ( @ _ ) } , help = > "Kicks a nick from the channel. Usage: mod kick <nick>" } ,
'ban' = > { subref = > sub { $ self - > ban ( @ _ ) } , help = > "Bans a nick from the channel. Cannot be used to set a custom banmask. Usage: mod ban <nick>" } ,
'mute' = > { subref = > sub { $ self - > mute ( @ _ ) } , help = > "Mutes a nick in the channel. Usage: mod mute <nick>" } ,
'unban' = > { subref = > sub { $ self - > unban ( @ _ ) } , help = > "Removes bans set by moderators. Cannot remove any other types of bans. Usage: mod unban <nick or mask>" } ,
'unmute' = > { subref = > sub { $ self - > unmute ( @ _ ) } , help = > "Removes mutes set by moderators. Cannot remove any other types of mutes. Usage: mod unmute <nick or mask>" } ,
2020-02-01 07:07:55 +01:00
'kb' = > { subref = > sub { $ self - > kb ( @ _ ) } , help = > "Kickbans a nick from the channel. Cannot be used to set a custom banmask. Usage: mod kb <nick>" } ,
2020-02-01 03:29:52 +01:00
} ;
}
sub unload {
my ( $ self ) = @ _ ;
$ self - > { pbot } - > { commands } - > unregister ( 'mod' ) ;
}
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." ;
}
}
sub list {
my ( $ self , $ stuff ) = @ _ ;
return "Available mod commands: " . join ', ' , sort keys % { $ self - > { commands } } ;
}
sub generic_command {
2020-02-01 07:03:50 +01:00
my ( $ self , $ stuff , $ command ) = @ _ ;
2020-02-01 03:29:52 +01:00
my $ channel = $ stuff - > { from } ;
if ( $ channel !~ m/^#/ ) {
$ channel = $ self - > { pbot } - > { interpreter } - > shift_arg ( $ stuff - > { arglist } ) ;
if ( not defined $ channel or $ channel !~ /^#/ ) {
return "Must specify channel from private message. Usage: mod $command <channel> <nick>" ;
}
}
2020-02-02 23:53:28 +01:00
return "I do not have OPs for this channel. I cannot do any moderation here."
if not $ self - > { pbot } - > { chanops } - > can_gain_ops ( $ channel ) ;
2020-02-02 23:56:37 +01:00
return "Voiced moderation is not enabled for this channel. Use `regset $channel.restrictedmod 1` to enable."
2020-02-02 23:53:28 +01:00
if not $ self - > { pbot } - > { registry } - > get_value ( $ channel , 'restrictedmod' ) ;
2020-02-01 03:29:52 +01:00
my $ hostmask = "$stuff->{nick}!$stuff->{user}\@$stuff->{host}" ;
my $ admin = $ self - > { pbot } - > { users } - > loggedin_admin ( $ channel , $ hostmask ) ;
my $ voiced = $ self - > { pbot } - > { nicklist } - > get_meta ( $ channel , $ stuff - > { nick } , '+v' ) ;
return "You must be voiced (usermode +v) or an admin to use this command." if not $ voiced and not $ admin ;
my $ target = $ self - > { pbot } - > { interpreter } - > shift_arg ( $ stuff - > { arglist } ) ;
if ( not defined $ target ) {
return "Missing target. Usage: mod $command <nick>" ;
}
2020-02-01 07:03:50 +01:00
if ( $ command eq 'unban' ) {
my $ reason = $ self - > { pbot } - > { chanops } - > checkban ( $ channel , $ target ) ;
if ( $ reason =~ m/moderator ban/ ) {
$ self - > { pbot } - > { chanops } - > unban_user ( $ target , $ channel , 1 ) ;
return "" ;
} else {
2020-02-01 10:04:12 +01:00
return "I don't think so. That ban was not set by a moderator." ;
2020-02-01 07:03:50 +01:00
}
} elsif ( $ command eq 'unmute' ) {
my $ reason = $ self - > { pbot } - > { chanops } - > checkmute ( $ channel , $ target ) ;
if ( $ reason =~ m/moderator mute/ ) {
$ self - > { pbot } - > { chanops } - > unmute_user ( $ target , $ channel , 1 ) ;
return "" ;
} else {
2020-02-01 10:04:12 +01:00
return "I don't think so. That mute was not set by a moderator." ;
2020-02-01 07:03:50 +01:00
}
}
2020-02-01 03:29:52 +01:00
my $ target_nicklist ;
if ( not $ self - > { pbot } - > { nicklist } - > is_present ( $ channel , $ target ) ) {
return "$stuff->{nick}: I do not see anybody named $target in this channel." ;
} else {
$ target_nicklist = $ self - > { pbot } - > { nicklist } - > { nicklist } - > { lc $ channel } - > { lc $ target } ;
}
my $ target_user = $ self - > { pbot } - > { users } - > find_user ( $ channel , $ target_nicklist - > { hostmask } ) ;
2020-02-01 03:53:03 +01:00
if ( ( defined $ target_user and $ target_user - > { level } > 0 or $ target_user - > { autoop } or $ target_user - > { autovoice } )
2020-02-01 03:29:52 +01:00
or $ target_nicklist - > { '+v' } or $ target_nicklist - > { '+o' }
or $ self - > { pbot } - > { antiflood } - > whitelisted ( $ channel , $ target_nicklist - > { hostmask } ) ) {
return "I don't think so."
}
2020-02-01 07:03:50 +01:00
if ( $ command eq 'kick' ) {
$ 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 ( "$stuff->{nick}!$stuff->{user}\@$stuff->{host}" ,
"doing something naughty (moderator ban)" , $ target , $ channel , 3600 * 24 , 1 ) ;
} elsif ( $ command eq 'mute' ) {
$ self - > { pbot } - > { chanops } - > mute_user_timed ( "$stuff->{nick}!$stuff->{user}\@$stuff->{host}" ,
"doing something naughty (moderator mute)" , $ target , $ channel , 3600 * 24 , 1 ) ;
2020-02-01 03:29:52 +01:00
}
return "" ;
}
sub kick {
my ( $ self , $ stuff ) = @ _ ;
2020-02-01 07:09:04 +01:00
return $ self - > generic_command ( $ stuff , 'kick' ) ;
2020-02-01 03:29:52 +01:00
}
sub ban {
my ( $ self , $ stuff ) = @ _ ;
2020-02-01 07:03:50 +01:00
return $ self - > generic_command ( $ stuff , 'ban' ) ;
2020-02-01 03:29:52 +01:00
}
sub mute {
my ( $ self , $ stuff ) = @ _ ;
2020-02-01 07:03:50 +01:00
return $ self - > generic_command ( $ stuff , 'mute' ) ;
}
sub unban {
my ( $ self , $ stuff ) = @ _ ;
return $ self - > generic_command ( $ stuff , 'unban' ) ;
}
sub unmute {
my ( $ self , $ stuff ) = @ _ ;
return $ self - > generic_command ( $ stuff , 'unmute' ) ;
}
sub kb {
my ( $ self , $ stuff ) = @ _ ;
2020-02-01 07:10:20 +01:00
my $ result = $ self - > ban ( dclone $ stuff ) ; # note: using copy of $stuff to preserve $stuff->{arglist} for $self->kick($stuff)
2020-02-01 07:03:50 +01:00
return $ result if length $ result ;
return $ self - > kick ( $ stuff ) ;
2020-02-01 03:29:52 +01:00
}
sub modcmd {
my ( $ self , $ from , $ nick , $ user , $ host , $ arguments , $ stuff ) = @ _ ;
my $ command = $ self - > { pbot } - > { interpreter } - > shift_arg ( $ stuff - > { arglist } ) // '' ;
$ command = lc $ command ;
if ( grep { $ _ eq $ command } keys % { $ self - > { commands } } ) {
return $ self - > { commands } - > { $ command } - > { subref } - > ( $ stuff ) ;
} else {
my $ commands = join ', ' , sort keys % { $ self - > { commands } } ;
if ( $ from !~ m/^#/ ) {
2020-02-01 03:45:34 +01:00
return "Usage: mod <channel> <command> [arguments]; commands are: $commands; see `mod help <command>` for more information." ;
2020-02-01 03:29:52 +01:00
} else {
2020-02-01 03:45:34 +01:00
return "Usage: mod <command> [arguments]; commands are: $commands; see `mod help <command>` for more information." ;
2020-02-01 03:29:52 +01:00
}
}
}
1 ;