2010-03-23 19:24:02 +01:00
# File: ChanOpCommands.pm
2010-03-24 07:47:40 +01:00
# Author: pragma_
2010-03-23 19:24:02 +01:00
#
# Purpose: Channel operator command subroutines.
2017-03-05 22:33:31 +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/.
2010-03-23 19:24:02 +01:00
package PBot::ChanOpCommands ;
2020-02-15 23:38:32 +01:00
2020-02-08 20:04:13 +01:00
use parent 'PBot::Class' ;
2010-03-23 19:24:02 +01:00
2020-02-08 20:04:13 +01:00
use warnings ; use strict ;
2019-07-11 03:40:53 +02:00
use feature 'unicode_strings' ;
2015-04-12 01:00:20 +02:00
use Time::Duration ;
2019-07-23 17:55:24 +02:00
use Time::HiRes qw/gettimeofday/ ;
2015-04-14 00:43:19 +02:00
2010-03-23 19:24:02 +01:00
sub initialize {
2020-02-15 23:38:32 +01:00
my ( $ self , % conf ) = @ _ ;
# register commands
$ self - > { pbot } - > { commands } - > register ( sub { $ self - > ban_user ( @ _ ) } , "ban" , 1 ) ;
$ self - > { pbot } - > { commands } - > register ( sub { $ self - > unban_user ( @ _ ) } , "unban" , 1 ) ;
$ 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 - > op_user ( @ _ ) } , "op" , 1 ) ;
$ self - > { pbot } - > { commands } - > register ( sub { $ self - > deop_user ( @ _ ) } , "deop" , 1 ) ;
$ self - > { pbot } - > { commands } - > register ( sub { $ self - > voice_user ( @ _ ) } , "voice" , 1 ) ;
$ self - > { pbot } - > { commands } - > register ( sub { $ self - > devoice_user ( @ _ ) } , "devoice" , 1 ) ;
$ self - > { pbot } - > { commands } - > register ( sub { $ self - > mode ( @ _ ) } , "mode" , 1 ) ;
$ self - > { pbot } - > { commands } - > register ( sub { $ self - > invite ( @ _ ) } , "invite" , 1 ) ;
# allow commands to set modes
$ self - > { pbot } - > { capabilities } - > add ( 'can-ban' , 'can-mode-b' , 1 ) ;
$ self - > { pbot } - > { capabilities } - > add ( 'can-unban' , 'can-mode-b' , 1 ) ;
$ self - > { pbot } - > { capabilities } - > add ( 'can-mute' , 'can-mode-q' , 1 ) ;
$ self - > { pbot } - > { capabilities } - > add ( 'can-unmute' , 'can-mode-q' , 1 ) ;
$ self - > { pbot } - > { capabilities } - > add ( 'can-op' , 'can-mode-o' , 1 ) ;
$ self - > { pbot } - > { capabilities } - > add ( 'can-deop' , 'can-mode-o' , 1 ) ;
$ self - > { pbot } - > { capabilities } - > add ( 'can-voice' , 'can-mode-v' , 1 ) ;
$ self - > { pbot } - > { capabilities } - > add ( 'can-devoice' , 'can-mode-v' , 1 ) ;
# create can-mode-any capabilities group
foreach my $ mode ( "a" .. "z" , "A" .. "Z" ) { $ self - > { pbot } - > { capabilities } - > add ( 'can-mode-any' , "can-mode-$mode" , 1 ) ; }
$ self - > { pbot } - > { capabilities } - > add ( 'can-mode-any' , 'can-mode' , 1 ) ;
# add to chanop capabilities group
$ self - > { pbot } - > { capabilities } - > add ( 'chanop' , 'can-ban' , 1 ) ;
$ self - > { pbot } - > { capabilities } - > add ( 'chanop' , 'can-unban' , 1 ) ;
$ self - > { pbot } - > { capabilities } - > add ( 'chanop' , 'can-mute' , 1 ) ;
$ self - > { pbot } - > { capabilities } - > add ( 'chanop' , 'can-unmute' , 1 ) ;
$ self - > { pbot } - > { capabilities } - > add ( 'chanop' , 'can-kick' , 1 ) ;
$ self - > { pbot } - > { capabilities } - > add ( 'chanop' , 'can-op' , 1 ) ;
$ self - > { pbot } - > { capabilities } - > add ( 'chanop' , 'can-deop' , 1 ) ;
$ self - > { pbot } - > { capabilities } - > add ( 'chanop' , 'can-voice' , 1 ) ;
$ self - > { pbot } - > { capabilities } - > add ( 'chanop' , 'can-devoice' , 1 ) ;
$ self - > { pbot } - > { capabilities } - > add ( 'chanop' , 'can-invite' , 1 ) ;
$ self - > { pbot } - > { capabilities } - > add ( 'chanop' , 'is-whitelisted' , 1 ) ;
# add to admin capability group
$ self - > { pbot } - > { capabilities } - > add ( 'admin' , 'chanop' , 1 ) ;
$ self - > { pbot } - > { capabilities } - > add ( 'admin' , 'can-mode' , 1 ) ;
$ self - > { pbot } - > { capabilities } - > add ( 'admin' , 'can-mode-any' , 1 ) ;
# allow users to use !unban * or !unmute *
$ self - > { pbot } - > { capabilities } - > add ( 'can-clear-bans' , undef , 1 ) ;
$ self - > { pbot } - > { capabilities } - > add ( 'can-clear-mutes' , undef , 1 ) ;
# allow admins to use !unban * or !unmute *
$ self - > { pbot } - > { capabilities } - > add ( 'admin' , 'can-clear-bans' , 1 ) ;
$ self - > { pbot } - > { capabilities } - > add ( 'admin' , 'can-clear-mutes' , 1 ) ;
# allows users to use wildcards in command
$ self - > { pbot } - > { capabilities } - > add ( 'can-op-wildcard' , undef , 1 ) ;
$ self - > { pbot } - > { capabilities } - > add ( 'can-voice-wildcard' , undef , 1 ) ;
$ self - > { pbot } - > { capabilities } - > add ( 'can-kick-wildcard' , undef , 1 ) ;
$ self - > { pbot } - > { capabilities } - > add ( 'admin' , 'can-kick-wildcard' , 1 ) ;
$ self - > { pbot } - > { capabilities } - > add ( 'admin' , 'can-op-wildcard' , 1 ) ;
$ self - > { pbot } - > { capabilities } - > add ( 'admin' , 'can-voice-wildcard' , 1 ) ;
$ self - > { pbot } - > { capabilities } - > add ( 'chanmod' , 'can-voice-wildcard' , 1 ) ;
$ self - > { invites } = { } ; # track who invited who in order to direct invite responses to them
# handle invite responses
$ self - > { pbot } - > { event_dispatcher } - > register_handler ( 'irc.inviting' , sub { $ self - > on_inviting ( @ _ ) } ) ;
$ self - > { pbot } - > { event_dispatcher } - > register_handler ( 'irc.useronchannel' , sub { $ self - > on_useronchannel ( @ _ ) } ) ;
$ self - > { pbot } - > { event_dispatcher } - > register_handler ( 'irc.nosuchnick' , sub { $ self - > on_nosuchnick ( @ _ ) } ) ;
2020-01-15 05:01:19 +01:00
}
sub on_inviting {
2020-02-15 23:38:32 +01:00
my ( $ self , $ event_type , $ event ) = @ _ ;
my ( $ botnick , $ target , $ channel ) = $ event - > { event } - > args ;
$ self - > { pbot } - > { logger } - > log ( "User $target invited to channel $channel.\n" ) ;
return 0 if not exists $ self - > { invites } - > { lc $ channel } or not exists $ self - > { invites } - > { lc $ channel } - > { lc $ target } ;
$ event - > { conn } - > privmsg ( $ self - > { invites } - > { lc $ channel } - > { lc $ target } , "$target invited to $channel." ) ;
delete $ self - > { invites } - > { lc $ channel } - > { lc $ target } ;
return 1 ;
2020-01-15 05:01:19 +01:00
}
sub on_useronchannel {
2020-02-15 23:38:32 +01:00
my ( $ self , $ event_type , $ event ) = @ _ ;
my ( $ botnick , $ target , $ channel ) = $ event - > { event } - > args ;
$ self - > { pbot } - > { logger } - > log ( "User $target is already on channel $channel.\n" ) ;
return 0 if not exists $ self - > { invites } - > { lc $ channel } or not exists $ self - > { invites } - > { lc $ channel } - > { lc $ target } ;
$ event - > { conn } - > privmsg ( $ self - > { invites } - > { lc $ channel } - > { lc $ target } , "$target is already on $channel." ) ;
delete $ self - > { invites } - > { lc $ channel } - > { lc $ target } ;
return 1 ;
2020-01-15 05:01:19 +01:00
}
sub on_nosuchnick {
2020-02-15 23:38:32 +01:00
my ( $ self , $ event_type , $ event ) = @ _ ;
my ( $ botnick , $ target , $ msg ) = $ event - > { event } - > args ;
2020-01-15 05:01:19 +01:00
2020-02-15 23:38:32 +01:00
$ self - > { pbot } - > { logger } - > log ( "$target: $msg\n" ) ;
2020-01-15 05:01:19 +01:00
2020-02-15 23:38:32 +01:00
my $ nick ;
foreach my $ channel ( keys % { $ self - > { invites } } ) {
if ( exists $ self - > { invites } - > { $ channel } - > { lc $ target } ) {
$ nick = $ self - > { invites } - > { $ channel } - > { lc $ target } ;
delete $ self - > { invites } - > { $ channel } - > { lc $ target } ;
last ;
}
2020-01-15 05:01:19 +01:00
}
2010-03-23 19:24:02 +01:00
2020-02-15 23:38:32 +01:00
return 0 if not defined $ nick ;
$ event - > { conn } - > privmsg ( $ nick , "$target: $msg" ) ;
return 1 ;
2019-12-29 08:17:15 +01:00
}
sub invite {
2020-02-15 23:38:32 +01:00
my ( $ self , $ from , $ nick , $ user , $ host , $ arguments , $ stuff ) = @ _ ;
my ( $ channel , $ target ) ;
if ( $ from !~ m/^#/ ) {
# from /msg
my $ usage = "Usage from /msg: invite <channel> [nick]; if you omit [nick] then you will be invited" ;
return $ usage if not length $ arguments ;
( $ channel , $ target ) = $ self - > { pbot } - > { interpreter } - > split_args ( $ stuff - > { arglist } , 2 ) ;
return "$channel is not a channel; $usage" if $ channel !~ m/^#/ ;
$ target = $ nick if not defined $ target ;
} else {
# in channel
return "Usage: invite [channel] <nick>" if not length $ arguments ;
# add current channel as default channel
$ self - > { pbot } - > { interpreter } - > unshift_arg ( $ stuff - > { arglist } , $ from ) if $ stuff - > { arglist } [ 0 ] !~ m/^#/ ;
( $ channel , $ target ) = $ self - > { pbot } - > { interpreter } - > split_args ( $ stuff - > { arglist } , 2 ) ;
}
$ self - > { invites } - > { lc $ channel } - > { lc $ target } = $ nick ;
$ self - > { pbot } - > { chanops } - > add_op_command ( $ channel , "sl invite $target $channel" ) ;
$ self - > { pbot } - > { chanops } - > gain_ops ( $ channel ) ;
return "" ; # responses handled by events
2019-12-26 15:08:39 +01:00
}
2020-01-12 03:02:00 +01:00
sub generic_mode_user {
2020-02-15 23:38:32 +01:00
my ( $ self , $ mode_flag , $ mode_name , $ channel , $ nick , $ stuff ) = @ _ ;
my $ result = '' ;
my ( $ flag , $ mode_char ) = $ mode_flag =~ m/(.)(.)/ ;
if ( $ channel !~ m/^#/ ) {
# from message
$ channel = $ self - > { pbot } - > { interpreter } - > shift_arg ( $ stuff - > { arglist } ) ;
if ( not defined $ channel ) { return "Usage from message: $mode_name <channel> [nick]" ; }
elsif ( $ channel !~ m/^#/ ) { return "$channel is not a channel. Usage from message: $mode_name <channel> [nick]" ; }
}
$ channel = lc $ channel ;
if ( not $ self - > { pbot } - > { chanops } - > can_gain_ops ( $ channel ) ) { return "I am not configured as an OP for $channel. See `chanset` command for more information." ; }
# add $nick to $args if no argument
if ( not $ self - > { pbot } - > { interpreter } - > arglist_size ( $ stuff - > { arglist } ) ) { $ self - > { pbot } - > { interpreter } - > unshift_arg ( $ stuff - > { arglist } , $ nick ) ; }
my $ max_modes = $ self - > { pbot } - > { ircd } - > { MODES } // 1 ;
my $ mode = $ flag ;
my $ list = '' ;
my $ i = 0 ;
foreach my $ targets ( $ self - > { pbot } - > { interpreter } - > unquoted_args ( $ stuff - > { arglist } ) ) {
foreach my $ target ( split /,/ , $ targets ) {
$ mode . = $ mode_char ;
$ list . = "$target " ;
$ i + + ;
if ( $ i >= $ max_modes ) {
my $ args = "$channel $mode $list" ;
$ stuff - > { arglist } = $ self - > { pbot } - > { interpreter } - > make_args ( $ args ) ;
$ result = $ self - > mode ( $ channel , $ nick , $ stuff - > { user } , $ stuff - > { host } , $ args , $ stuff ) ;
$ mode = $ flag ;
$ list = '' ;
$ i = 0 ;
last if $ result ne '' and $ result ne 'Done.' ;
}
}
2020-01-12 02:46:44 +01:00
}
2020-02-15 23:38:32 +01:00
if ( $ i ) {
2020-01-12 02:46:44 +01:00
my $ args = "$channel $mode $list" ;
$ stuff - > { arglist } = $ self - > { pbot } - > { interpreter } - > make_args ( $ args ) ;
2020-02-03 18:50:38 +01:00
$ result = $ self - > mode ( $ channel , $ nick , $ stuff - > { user } , $ stuff - > { host } , $ args , $ stuff ) ;
2020-01-12 02:46:44 +01:00
}
2020-02-15 23:38:32 +01:00
return $ result ;
2020-01-12 02:46:44 +01:00
}
2020-01-12 03:02:00 +01:00
sub op_user {
2020-02-15 23:38:32 +01:00
my ( $ self , $ from , $ nick , $ user , $ host , $ arguments , $ stuff ) = @ _ ;
return $ self - > generic_mode_user ( '+o' , 'op' , $ from , $ nick , $ stuff ) ;
2020-01-12 03:02:00 +01:00
}
2020-01-12 02:46:44 +01:00
2020-01-12 03:02:00 +01:00
sub deop_user {
2020-02-15 23:38:32 +01:00
my ( $ self , $ from , $ nick , $ user , $ host , $ arguments , $ stuff ) = @ _ ;
return $ self - > generic_mode_user ( '-o' , 'deop' , $ from , $ nick , $ stuff ) ;
2020-01-12 03:02:00 +01:00
}
2020-01-12 02:46:44 +01:00
2020-01-12 03:02:00 +01:00
sub voice_user {
2020-02-15 23:38:32 +01:00
my ( $ self , $ from , $ nick , $ user , $ host , $ arguments , $ stuff ) = @ _ ;
return $ self - > generic_mode_user ( '+v' , 'voice' , $ from , $ nick , $ stuff ) ;
2020-01-12 03:02:00 +01:00
}
2020-01-12 02:46:44 +01:00
2020-01-12 03:02:00 +01:00
sub devoice_user {
2020-02-15 23:38:32 +01:00
my ( $ self , $ from , $ nick , $ user , $ host , $ arguments , $ stuff ) = @ _ ;
return $ self - > generic_mode_user ( '-v' , 'devoice' , $ from , $ nick , $ stuff ) ;
2020-01-12 02:46:44 +01:00
}
2019-12-26 15:08:39 +01:00
sub mode {
2020-02-15 23:38:32 +01:00
my ( $ self , $ from , $ nick , $ user , $ host , $ arguments , $ stuff ) = @ _ ;
2019-12-27 04:24:35 +01:00
2020-02-15 23:38:32 +01:00
if ( not length $ arguments ) { return "Usage: mode [channel] <arguments>" ; }
2019-12-27 04:24:35 +01:00
2020-02-15 23:38:32 +01:00
# add current channel as default channel
if ( $ stuff - > { arglist } [ 0 ] !~ m/^#/ ) {
if ( $ from =~ m/^#/ ) { $ self - > { pbot } - > { interpreter } - > unshift_arg ( $ stuff - > { arglist } , $ from ) ; }
else { return "Usage from private message: mode <channel> <arguments>" ; }
2019-12-27 04:24:35 +01:00
}
2020-02-15 23:38:32 +01:00
my ( $ channel , $ modes , $ args ) = $ self - > { pbot } - > { interpreter } - > split_args ( $ stuff - > { arglist } , 3 ) ;
my @ targets = split /\s+/ , $ args if defined $ args ;
my $ modifier ;
my $ i = 0 ;
my $ arg = 0 ;
2020-02-03 18:50:38 +01:00
2020-02-15 23:38:32 +01:00
my ( $ new_modes , $ new_targets ) = ( "" , "" ) ;
my $ max_modes = $ self - > { pbot } - > { ircd } - > { MODES } // 1 ;
2019-12-27 04:24:35 +01:00
2020-02-15 23:38:32 +01:00
my $ u = $ self - > { pbot } - > { users } - > loggedin ( $ channel , "$nick!$user\@$host" ) ;
2019-12-27 04:24:35 +01:00
2020-02-15 23:38:32 +01:00
while ( $ modes =~ m/(.)/g ) {
my $ mode = $ 1 ;
2019-12-27 04:24:35 +01:00
2020-02-15 23:38:32 +01:00
if ( $ mode eq '-' or $ mode eq '+' ) {
$ modifier = $ mode ;
$ new_modes . = $ mode ;
next ;
2020-02-06 02:38:56 +01:00
}
2020-02-15 23:38:32 +01:00
if ( not $ self - > { pbot } - > { capabilities } - > userhas ( $ u , "can-mode-$mode" ) ) {
return "/msg $nick Your user account does not have the can-mode-$mode capability required to set this mode." ;
2020-02-06 02:38:56 +01:00
}
2020-02-15 23:38:32 +01:00
my $ target = $ targets [ $ arg + + ] // "" ;
if ( ( $ mode eq 'v' or $ mode eq 'o' ) and $ target =~ m/\*/ ) {
# wildcard used; find all matching nicks; test against whitelist, etc
my $ q_target = lc quotemeta $ target ;
$ q_target =~ s/\\\*/.*/g ;
$ channel = lc $ channel ;
if ( not exists $ self - > { pbot } - > { nicklist } - > { nicklist } - > { $ channel } ) { return "I have no nicklist for channel $channel; cannot use wildcard." ; }
my $ u = $ self - > { pbot } - > { users } - > loggedin ( $ channel , "$nick!$user\@$host" ) ;
if ( $ mode eq 'v' ) {
if ( not $ self - > { pbot } - > { capabilities } - > userhas ( $ u , 'can-voice-wildcard' ) ) {
return "/msg $nick Using wildcards with `mode v` requires the can-voice-wildcard capability, which your user account does not have." ;
}
} else {
if ( not $ self - > { pbot } - > { capabilities } - > userhas ( $ u , 'can-op-wildcard' ) ) {
return "/msg $nick Using wildcards with `mode o` requires the can-op-wildcard capability, which your user account does not have." ;
}
}
foreach my $ n ( keys % { $ self - > { pbot } - > { nicklist } - > { nicklist } - > { $ channel } } ) {
if ( $ n =~ m/^$q_target$/ ) {
my $ nick_data = $ self - > { pbot } - > { nicklist } - > { nicklist } - > { $ channel } - > { $ n } ;
if ( $ modifier eq '-' ) {
# removing mode -- check against whitelist, etc
next if $ nick_data - > { nick } eq $ self - > { pbot } - > { registry } - > get_value ( 'irc' , 'botnick' ) ;
my $ u = $ self - > { pbot } - > { users } - > loggedin ( $ channel , $ nick_data - > { hostmask } ) ;
next if $ self - > { pbot } - > { capabilities } - > userhas ( $ u , 'is-whitelisted' ) ;
}
# skip nick if already has mode set/unset
if ( $ modifier eq '+' ) { next if exists $ nick_data - > { "+$mode" } ; }
else { next unless exists $ nick_data - > { "+$mode" } ; }
$ new_modes = $ modifier if not length $ new_modes ;
$ new_modes . = $ mode ;
$ new_targets . = "$self->{pbot}->{nicklist}->{nicklist}->{$channel}->{$n}->{nick} " ;
$ i + + ;
if ( $ i == $ max_modes ) {
$ self - > { pbot } - > { chanops } - > add_op_command ( $ channel , "mode $channel $new_modes $new_targets" ) ;
$ new_modes = "" ;
$ new_targets = "" ;
$ i = 0 ;
}
}
}
} else {
# no wildcard used; explicit mode requested - no whitelist checking
$ new_modes . = $ mode ;
$ new_targets . = "$target " if length $ target ;
$ i + + ;
if ( $ i == $ max_modes ) {
$ self - > { pbot } - > { chanops } - > add_op_command ( $ channel , "mode $channel $new_modes $new_targets" ) ;
$ new_modes = "" ;
$ new_targets = "" ;
$ i = 0 ;
}
2019-12-27 04:24:35 +01:00
}
}
2020-02-15 23:38:32 +01:00
if ( $ i ) { $ self - > { pbot } - > { chanops } - > add_op_command ( $ channel , "mode $channel $new_modes $new_targets" ) ; }
2019-12-27 04:24:35 +01:00
2020-02-15 23:38:32 +01:00
$ self - > { pbot } - > { chanops } - > gain_ops ( $ channel ) ;
2019-12-26 15:08:39 +01:00
2020-02-15 23:38:32 +01:00
if ( $ from !~ m/^#/ ) { return "Done." ; }
else { return "" ; }
2019-07-23 17:55:24 +02:00
}
2010-06-18 09:03:16 +02:00
sub ban_user {
2020-02-15 23:38:32 +01:00
my ( $ self , $ from , $ nick , $ user , $ host , $ arguments , $ stuff ) = @ _ ;
my ( $ target , $ channel , $ length ) = $ self - > { pbot } - > { interpreter } - > split_args ( $ stuff - > { arglist } , 3 ) ;
2010-03-23 19:24:02 +01:00
2020-02-15 23:38:32 +01:00
$ channel = '' if not defined $ channel ;
$ length = '' if not defined $ length ;
2017-04-11 04:13:56 +02:00
2020-02-15 23:38:32 +01:00
if ( not defined $ from ) {
$ self - > { pbot } - > { logger } - > log ( "Command missing ~from parameter!\n" ) ;
return "" ;
}
if ( $ channel !~ m/^#/ ) {
$ length = "$channel $length" ;
$ length = undef if $ length eq ' ' ;
$ channel = exists $ stuff - > { admin_channel_override } ? $ stuff - > { admin_channel_override } : $ from ;
}
$ channel = exists $ stuff - > { admin_channel_override } ? $ stuff - > { admin_channel_override } : $ from if not defined $ channel or not length $ channel ;
if ( not defined $ target ) { return "Usage: ban <mask> [channel [timeout (default: 24 hours)]]" ; }
my $ no_length = 0 ;
if ( not defined $ length ) {
2020-04-29 06:33:49 +02:00
# TODO: user account length override
2020-02-15 23:38:32 +01:00
$ 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 ;
2019-07-23 17:55:24 +02:00
} else {
2020-02-15 23:38:32 +01:00
my $ error ;
( $ length , $ error ) = $ self - > { pbot } - > { parsedate } - > parsedate ( $ length ) ;
return $ error if defined $ error ;
2019-07-23 17:55:24 +02:00
}
2018-06-06 07:59:33 +02:00
2020-02-15 23:38:32 +01:00
$ channel = lc $ channel ;
$ target = lc $ target ;
my $ botnick = $ self - > { pbot } - > { registry } - > get_value ( 'irc' , 'botnick' ) ;
return "I don't think so." if $ target =~ /^\Q$botnick\E!/i ;
my $ result = '' ;
my $ sep = '' ;
my @ targets = split /,/ , $ target ;
my $ immediately = @ targets > 1 ? 0 : 1 ;
my $ duration ;
foreach my $ t ( @ targets ) {
2020-04-29 06:33:49 +02:00
my $ mask = lc $ self - > { pbot } - > { banlist } - > nick_to_banmask ( $ t ) ;
my $ timeout = $ self - > { pbot } - > { banlist } - > { banlist } - > get_data ( $ channel , $ mask , 'timeout' ) // 0 ;
2020-02-15 23:38:32 +01:00
2020-04-29 06:33:49 +02:00
if ( $ no_length && $ timeout > 0 ) {
my $ d = duration ( $ timeout - gettimeofday ) ;
2020-02-15 23:38:32 +01:00
$ result . = "$sep$mask has $d remaining on their $channel ban" ;
$ sep = '; ' ;
} else {
2020-04-29 06:33:49 +02:00
$ self - > { pbot } - > { banlist } - > ban_user_timed ( $ channel , 'b' , $ mask , $ length , "$nick!$user\@$host" , undef , $ immediately ) ;
2020-02-15 23:38:32 +01:00
$ duration = $ length > 0 ? duration $ length : 'all eternity' ;
if ( $ immediately ) {
$ result . = "$sep$mask banned in $channel for $duration" ;
$ sep = '; ' ;
} else {
$ result . = "$sep$mask" ;
$ sep = ', ' ;
}
}
}
2015-05-07 06:13:39 +02:00
2020-02-15 23:38:32 +01:00
if ( not $ immediately ) {
$ result . = " banned in $channel for $duration" ;
2020-04-29 06:33:49 +02:00
$ self - > { pbot } - > { banlist } - > flush_ban_queue ;
2020-02-15 23:38:32 +01:00
}
$ result = "/msg $nick $result" if $ result !~ m/remaining on their/ ;
return $ result ;
2010-03-23 19:24:02 +01:00
}
2010-06-18 09:03:16 +02:00
sub unban_user {
2020-02-15 23:38:32 +01:00
my $ self = shift ;
my ( $ from , $ nick , $ user , $ host , $ arguments , $ stuff ) = @ _ ;
2010-03-23 19:24:02 +01:00
2020-02-15 23:38:32 +01:00
if ( not defined $ from ) {
$ self - > { pbot } - > { logger } - > log ( "Command missing ~from parameter!\n" ) ;
return "" ;
}
my ( $ target , $ channel , $ immediately ) = $ self - > { pbot } - > { interpreter } - > split_args ( $ stuff - > { arglist } , 3 ) ;
if ( defined $ target and defined $ channel and $ channel !~ /^#/ ) {
my $ temp = $ target ;
$ target = $ channel ;
$ channel = $ temp ;
}
if ( not defined $ target ) { return "Usage: unban <nick/mask> [channel [false value to use unban queue]]" ; }
$ channel = exists $ stuff - > { admin_channel_override } ? $ stuff - > { admin_channel_override } : $ from if not defined $ channel ;
$ immediately = 1 if not defined $ immediately ;
return "Usage for /msg: unban <nick/mask> <channel> [false value to use unban queue]" if $ channel !~ /^#/ ;
my @ targets = split /,/ , $ target ;
$ immediately = 0 if @ targets > 1 ;
foreach my $ t ( @ targets ) {
if ( $ t eq '*' ) {
my $ u = $ self - > { pbot } - > { users } - > loggedin ( $ channel , "$nick!$user\@$host" ) ;
if ( not $ self - > { pbot } - > { capabilities } - > userhas ( $ u , 'can-clear-bans' ) ) {
return "/msg $nick Clearing the channel bans requires the can-clear-bans capability, which your user account does not have." ;
}
$ channel = lc $ channel ;
2020-04-29 06:33:49 +02:00
if ( $ self - > { pbot } - > { banlist } - > { banlist } - > exists ( $ channel ) ) {
2020-02-15 23:38:32 +01:00
$ immediately = 0 ;
2020-04-29 06:33:49 +02:00
foreach my $ banmask ( $ self - > { pbot } - > { banlist } - > { banlist } - > get_keys ( $ channel ) ) {
$ self - > { pbot } - > { banlist } - > unban_user ( $ banmask , 'b' , $ channel , $ immediately ) ;
}
2020-02-15 23:38:32 +01:00
last ;
}
} else {
2020-04-30 23:27:10 +02:00
$ self - > { pbot } - > { banlist } - > unban_user ( $ channel , 'b' , $ t , $ immediately ) ;
2020-02-06 02:03:39 +01:00
}
}
2018-06-06 07:59:33 +02:00
2020-04-29 06:33:49 +02:00
$ self - > { pbot } - > { banlist } - > flush_unban_queue if not $ immediately ;
2020-02-15 23:38:32 +01:00
return "/msg $nick $target has been unbanned from $channel." ;
2010-03-23 19:24:02 +01:00
}
2015-05-27 19:45:43 +02:00
sub mute_user {
2020-02-15 23:38:32 +01:00
my ( $ self , $ from , $ nick , $ user , $ host , $ arguments , $ stuff ) = @ _ ;
my ( $ target , $ channel , $ length ) = $ self - > { pbot } - > { interpreter } - > split_args ( $ stuff - > { arglist } , 3 ) ;
2015-05-27 19:45:43 +02:00
2020-04-06 01:58:56 +02:00
$ channel = '' if not defined $ channel ;
2020-02-15 23:38:32 +01:00
if ( not defined $ from ) {
$ self - > { pbot } - > { logger } - > log ( "Command missing ~from parameter!\n" ) ;
return "" ;
}
2020-04-06 01:58:56 +02:00
if ( not length $ channel and $ from !~ m/^#/ ) { return "Usage from private message: mute <mask> <channel> [timeout (default: 24 hours)]" ; }
2020-02-15 23:38:32 +01:00
if ( $ channel !~ m/^#/ ) {
2020-04-06 01:58:56 +02:00
$ length = $ channel . ' ' . ( defined $ length ? $ length : '' ) ;
2020-02-15 23:38:32 +01:00
$ length = undef if $ length eq ' ' ;
$ channel = exists $ stuff - > { admin_channel_override } ? $ stuff - > { admin_channel_override } : $ from ;
}
$ channel = exists $ stuff - > { admin_channel_override } ? $ stuff - > { admin_channel_override } : $ from if not defined $ channel ;
if ( $ channel !~ m/^#/ ) { return "Please specify a channel." ; }
if ( not defined $ target ) { return "Usage: mute <mask> [channel [timeout (default: 24 hours)]]" ; }
my $ no_length = 0 ;
if ( not defined $ length ) {
$ length = $ self - > { pbot } - > { registry } - > get_value ( $ channel , 'default_mute_timeout' , 0 , $ stuff )
// $ self - > { pbot } - > { registry } - > get_value ( 'general' , 'default_mute_timeout' , 0 , $ stuff ) // 60 * 60 * 24 ; # 24 hours
$ no_length = 1 ;
2019-07-23 17:55:24 +02:00
} else {
2020-02-15 23:38:32 +01:00
my $ error ;
( $ length , $ error ) = $ self - > { pbot } - > { parsedate } - > parsedate ( $ length ) ;
return $ error if defined $ error ;
}
$ channel = lc $ channel ;
$ target = lc $ target ;
my $ botnick = $ self - > { pbot } - > { registry } - > get_value ( 'irc' , 'botnick' ) ;
return "I don't think so." if $ target =~ /^\Q$botnick\E!/i ;
my $ result = '' ;
my $ sep = '' ;
my @ targets = split /,/ , $ target ;
my $ immediately = @ targets > 1 ? 0 : 1 ;
my $ duration ;
foreach my $ t ( @ targets ) {
2020-04-29 06:33:49 +02:00
my $ mask = lc $ self - > { pbot } - > { banlist } - > nick_to_banmask ( $ t ) ;
my $ timeout = $ self - > { pbot } - > { banlist } - > { quietlist } - > get_data ( $ channel , $ mask , 'timeout' ) // 0 ;
2020-02-15 23:38:32 +01:00
2020-04-29 06:33:49 +02:00
if ( $ no_length && $ timeout > 0 ) {
my $ d = duration ( $ timeout - gettimeofday ) ;
2020-02-15 23:38:32 +01:00
$ result . = "$sep$mask has $d remaining on their $channel mute" ;
$ sep = '; ' ;
} else {
2020-04-29 06:33:49 +02:00
$ self - > { pbot } - > { banlist } - > ban_user_timed ( $ channel , 'q' , $ t , $ length , "$nick!$user\@$host" , undef , $ immediately ) ;
2020-02-15 23:38:32 +01:00
$ duration = $ length > 0 ? duration $ length : 'all eternity' ;
if ( $ immediately ) {
$ result . = "$sep$mask muted in $channel for $duration" ;
$ sep = '; ' ;
} else {
$ result . = "$sep$mask" ;
$ sep = ', ' ;
}
}
2019-07-23 17:55:24 +02:00
}
2018-06-06 07:59:33 +02:00
2020-02-15 23:38:32 +01:00
if ( not $ immediately ) {
$ result . = " muted in $channel for $duration" ;
2020-04-29 06:33:49 +02:00
$ self - > { pbot } - > { banlist } - > flush_ban_queue ;
2020-02-15 23:38:32 +01:00
}
2015-05-27 19:45:43 +02:00
2020-02-15 23:38:32 +01:00
$ result = "/msg $nick $result" if $ result !~ m/remaining on their/ ;
return $ result ;
2015-05-27 19:45:43 +02:00
}
sub unmute_user {
2020-02-15 23:38:32 +01:00
my $ self = shift ;
my ( $ from , $ nick , $ user , $ host , $ arguments , $ stuff ) = @ _ ;
2015-05-27 19:45:43 +02:00
2020-02-15 23:38:32 +01:00
if ( not defined $ from ) {
$ self - > { pbot } - > { logger } - > log ( "Command missing ~from parameter!\n" ) ;
return "" ;
}
my ( $ target , $ channel , $ immediately ) = $ self - > { pbot } - > { interpreter } - > split_args ( $ stuff - > { arglist } , 3 ) ;
if ( defined $ target and defined $ channel and $ channel !~ /^#/ ) {
my $ temp = $ target ;
$ target = $ channel ;
$ channel = $ temp ;
}
if ( not defined $ target ) { return "Usage: unmute <nick/mask> [channel [false value to use unban queue]]" ; }
$ channel = exists $ stuff - > { admin_channel_override } ? $ stuff - > { admin_channel_override } : $ from if not defined $ channel ;
$ immediately = 1 if not defined $ immediately ;
return "Usage for /msg: unmute <nick/mask> <channel> [false value to use unban queue]" if $ channel !~ /^#/ ;
my @ targets = split /,/ , $ target ;
$ immediately = 0 if @ targets > 1 ;
foreach my $ t ( @ targets ) {
if ( $ t eq '*' ) {
my $ u = $ self - > { pbot } - > { users } - > loggedin ( $ channel , "$nick!$user\@$host" ) ;
if ( not $ self - > { pbot } - > { capabilities } - > userhas ( $ u , 'can-clear-mutes' ) ) {
return "/msg $nick Clearing the channel mutes requires the can-clear-mutes capability, which your user account does not have." ;
}
$ channel = lc $ channel ;
2020-04-29 06:33:49 +02:00
if ( $ self - > { pbot } - > { banlist } - > { quietlist } - > exists ( $ channel ) ) {
2020-02-15 23:38:32 +01:00
$ immediately = 0 ;
2020-04-29 06:33:49 +02:00
foreach my $ banmask ( $ self - > { pbot } - > { banlist } - > { quietlist } - > get_keys ( $ channel ) ) {
$ self - > { pbot } - > { banlist } - > unban_user ( $ channel , 'q' , $ banmask , $ immediately ) ;
}
2020-02-15 23:38:32 +01:00
last ;
}
} else {
2020-04-29 06:33:49 +02:00
$ self - > { pbot } - > { banlist } - > unban_user ( $ channel , 'q' , $ t , $ immediately ) ;
2020-02-06 02:03:39 +01:00
}
}
2018-06-06 07:59:33 +02:00
2020-04-29 06:33:49 +02:00
$ self - > { pbot } - > { banlist } - > flush_unban_queue if not $ immediately ;
2020-02-15 23:38:32 +01:00
return "/msg $nick $target has been unmuted in $channel." ;
2015-05-27 19:45:43 +02:00
}
2010-03-23 19:24:02 +01:00
sub kick_user {
2020-02-15 23:38:32 +01:00
my $ self = shift ;
my ( $ from , $ nick , $ user , $ host , $ arguments , $ stuff ) = @ _ ;
2010-03-23 19:24:02 +01:00
2020-02-15 23:38:32 +01:00
if ( not defined $ from ) {
$ self - > { pbot } - > { logger } - > log ( "Command missing ~from parameter!\n" ) ;
return "" ;
}
2010-03-23 19:24:02 +01:00
2020-02-15 23:38:32 +01:00
my ( $ channel , $ victim , $ reason ) ;
2016-08-29 07:36:46 +02:00
2020-02-15 23:38:32 +01:00
if ( not $ from =~ /^#/ ) {
# used in private message
if ( not $ arguments =~ s/^(^#\S+) (\S+)\s*// ) { return "Usage from private message: kick <channel> <nick> [reason]" ; }
( $ channel , $ victim ) = ( $ 1 , $ 2 ) ;
2016-08-29 07:36:46 +02:00
} else {
2020-02-15 23:38:32 +01:00
# used in channel
if ( $ arguments =~ s/^(#\S+)\s+(\S+)\s*// ) { ( $ channel , $ victim ) = ( $ 1 , $ 2 ) ; }
elsif ( $ arguments =~ s/^(\S+)\s*// ) { ( $ victim , $ channel ) = ( $ 1 , exists $ stuff - > { admin_channel_override } ? $ stuff - > { admin_channel_override } : $ from ) ; }
else { return "Usage: kick [channel] <nick> [reason]" ; }
2016-08-29 07:36:46 +02:00
}
2020-02-15 23:38:32 +01:00
$ reason = $ arguments ;
# If the user is too stupid to remember the order of the arguments,
# we can help them out by seeing if they put the channel in the reason.
if ( $ reason =~ s/^(#\S+)\s*// ) { $ channel = $ 1 ; }
my @ insults ;
if ( not length $ reason ) {
if ( open my $ fh , '<' , $ self - > { pbot } - > { registry } - > get_value ( 'general' , 'module_dir' ) . '/insults.txt' ) {
@ insults = <$fh> ;
close $ fh ;
$ reason = $ insults [ rand @ insults ] ;
$ reason =~ s/\s+$// ;
} else {
$ reason = 'Bye!' ;
2019-12-31 03:17:35 +01:00
}
}
2020-02-15 23:38:32 +01:00
my @ nicks = split /,/ , $ victim ;
foreach my $ n ( @ nicks ) {
if ( $ n =~ m/\*/ ) {
# wildcard used; find all matching nicks; test against whitelist, etc
my $ q_target = lc quotemeta $ n ;
$ q_target =~ s/\\\*/.*/g ;
$ channel = lc $ channel ;
if ( not exists $ self - > { pbot } - > { nicklist } - > { nicklist } - > { $ channel } ) { return "I have no nicklist for channel $channel; cannot use wildcard." ; }
my $ u = $ self - > { pbot } - > { users } - > loggedin ( $ channel , "$nick!$user\@$host" ) ;
if ( not $ self - > { pbot } - > { capabilities } - > userhas ( $ u , 'can-kick-wildcard' ) ) {
return "/msg $nick Using wildcards with `kick` requires the can-kick-wildcard capability, which your user account does not have." ;
}
foreach my $ nl ( keys % { $ self - > { pbot } - > { nicklist } - > { nicklist } - > { $ channel } } ) {
if ( $ nl =~ m/^$q_target$/ ) {
my $ nick_data = $ self - > { pbot } - > { nicklist } - > { nicklist } - > { $ channel } - > { $ nl } ;
next if $ nick_data - > { nick } eq $ self - > { pbot } - > { registry } - > get_value ( 'irc' , 'botnick' ) ;
my $ u = $ self - > { pbot } - > { users } - > loggedin ( $ channel , $ nick_data - > { hostmask } ) ;
next if $ self - > { pbot } - > { capabilities } - > userhas ( $ u , 'is-whitelisted' ) ;
$ self - > { pbot } - > { chanops } - > add_op_command ( $ channel , "kick $channel $nl $reason" ) ;
}
}
} else {
# no wildcard used, explicit kick
$ self - > { pbot } - > { chanops } - > add_op_command ( $ channel , "kick $channel $n $reason" ) ;
}
# randomize next kick reason
if ( @ insults ) {
$ reason = $ insults [ rand @ insults ] ;
$ reason =~ s/\s+$// ;
}
2017-11-11 21:59:27 +01:00
}
2017-11-03 20:28:41 +01:00
2020-02-15 23:38:32 +01:00
$ self - > { pbot } - > { chanops } - > gain_ops ( $ channel ) ;
return "" ;
2010-03-23 19:24:02 +01:00
}
1 ;