# ho-mkill.pl # # $Id: ho_mkill.pl,v 1.8 2004/08/22 20:19:26 jvunder REL_0_3 $ # # Part of the Hybrid Oper Script Collection. # # This provides a /MKILL command. # --------------------------------------------------------------------- use strict; use vars qw($VERSION %IRSSI $SCRIPT_NAME); use Irssi; use Irssi::Irc; use HOSC::again; use HOSC::again 'HOSC::Base'; use HOSC::again 'HOSC::Tools'; use Getopt::Long; # --------------------------------------------------------------------- ($VERSION) = '$Revision: 1.8 $' =~ / (\d+\.\d+) /; %IRSSI = ( authors => 'Garion', contact => 'garion@efnet.nl', name => 'ho_mkill.pl', description => 'Masskill command for a channel.', license => 'Public Domain', url => 'http://www.garion.org/irssi/', changed => '12 January 2003 21:53:46', ); $SCRIPT_NAME = 'Masskill'; my $args; my $who_data; # --------------------------------------------------------------------- sub cmd_mkill { my ($cmdline, $server, $chan) = @_; if ($cmdline =~ /^help/) { return print_help(); } $args = process_arguments($cmdline); if ($args->{help}) { return print_help(); } if (!$server) { ho_print_error("Please use /MKILL from a window of the server you want to masskill on."); return; } if (!defined $args->{channel}) { ho_print_error(" argument missing. See /MKILL HELP for help."); return; } my $channel = $server->channel_find($args->{channel}); if (!defined $channel) { ho_print_error("You are not on channel " . $args->{channel} . " on this server."); return; } $args->{channel_obj} = $channel; $args->{server_obj} = $server; if (!defined $args->{reason}) { $args->{reason} = Irssi::settings_get_str('ho_mkill_reason'); } # If we're going for a takeover, we don't need to send a WHO because # we'll kill all other clients anyway. if ($args->{takeover}) { perform_takeover(); return; } if (defined $args->{hostmask} && $args->{hostmask} =~ /^(?:(.+)!)?(.+)@(.+)$/ ) { $args->{nick} = $1 ? $1 : "*"; $args->{user} = $2; $args->{host} = $3; } else { ho_print_error("Missing or invalid hostmask. See /MKILL HELP for help."); return; } ho_print('Simulation enabled.') if $args->{simulation}; ho_print('Masskilling clients matching ' . $args->{nick} . "!" . $args->{user} . "@" . $args->{host} . " in " . $args->{channel} . " for reason '" . $args->{reason} . "'."); # Get rid of all previous WHO data. delete $who_data->{$_} for keys %$who_data; # Enable the redirects; otherwise we may end up killing opers. $server->redirect_event('who', 1, $args->{channel}, 0, undef, { 'event 352' => 'redir event_who_line', 'event 315' => 'redir event_who_end', '' => 'event empty', } ); ho_print("Sending WHO.") if $args->{verbose}; $server->send_raw_now("WHO " . $args->{channel}); } # Need to capture who is opered via the output of WHO. sub event_who_line { my ($server, $data, $nick, $address) = @_; my @tokens = split / /, $data; my $nick = $tokens[5]; $who_data->{$nick} = { user => $tokens[2], host => $tokens[3], server => $tokens[4], userhost => $tokens[2] . '@' . $tokens[3], }; $who_data->{$nick}->{opered} = 1 if $tokens[6] =~ /\*/; $who_data->{$nick}->{opped} = 1 if $tokens[6] =~ /@/; Irssi::signal_stop(); } sub event_who_end { Irssi::signal_stop(); perform_masskill(); } sub perform_takeover { ho_print("Taking over " . $args->{channel}); # No need for /WHO data, just use internal irssi channel data. if ($args->{takeover}) { my @nicks = $args->{channel_obj}->nicks(); for my $nick (@nicks) { # Don't kill myself! next if $nick->{nick} eq $args->{server_obj}->{nick}; my $cmd = "KILL " . $nick->{nick} . " :" . $args->{reason}; if ($args->{simulation}) { ho_print($cmd); } else { $args->{server_obj}->send_raw_now($cmd); } } ho_print("Killed " . (scalar @nicks - 1) . " clients."); if ($args->{simulation}) { ho_print("PART " . $args->{channel}); ho_print("JOIN " . $args->{channel}); } else { $args->{server_obj}->send_raw_now("PART " . $args->{channel}); $args->{server_obj}->send_raw_now("JOIN " . $args->{channel}); } ho_print("Channel takeover of " . $args->{channel} . " complete."); return; } } sub perform_masskill { ho_print("Performing masskill."); my $num_kills = 0; # Normal masskill. Uses WHO #channel data. for my $nick (keys %$who_data) { # Don't kill myself! next if $nick eq $args->{server_obj}->{nick}; my $hostmask = $who_data->{$nick}->{userhost}; if (Irssi::mask_match_address($args->{nick} . '!' . $args->{user} . '@' . $args->{host}, $nick, $hostmask) ) { if ($who_data->{$nick}->{opped} && !$args->{ops}) { ho_print($nick . " is opped. Not killing.") if $args->{verbose}; next; } if ($who_data->{$nick}->{opered} && !$args->{opers}) { ho_print($nick . " is an oper. Not killing.") if $args->{verbose}; next; } my $cmd = "KILL $nick :" . $args->{reason}; if ($args->{simulation}) { ho_print($cmd); } else { $args->{server_obj}->send_raw_now($cmd); } $num_kills++; } } delete $who_data->{$_} for keys %$who_data; ho_print("Done. Killed $num_kills client" . ($num_kills == 1 ? '' : 's') . "."); } sub process_arguments { my ($arguments) = @_; my $opt; local @ARGV = split / /, $arguments; my $res = GetOptions( 'ops' => \$opt->{ops}, 'opers' => \$opt->{opers}, 'takeover' => \$opt->{takeover}, 'sim' => \$opt->{simulation}, 'simulate' => \$opt->{simulation}, 'simulation' => \$opt->{simulation}, 'verbose' => \$opt->{verbose}, ); # Get the channel. if (@ARGV) { $opt->{channel} = shift @ARGV; } # Get the hostmask. if (@ARGV) { $opt->{hostmask} = shift @ARGV; } # Reassemble the reason. for my $arg (@ARGV) { $opt->{reason} .= $arg . " "; } $opt->{reason} =~ s/ $// if defined $opt->{reason}; return $opt; } # --------------------------------------------------------------------- ho_print_init_begin($SCRIPT_NAME); Irssi::command_bind('mkill', 'cmd_mkill'); Irssi::settings_add_str('ho', 'ho_mkill_reason', 'Plonk!'); Irssi::signal_add({ 'redir event_who_line' => \&event_who_line }); Irssi::signal_add({ 'redir event_who_end' => \&event_who_end }); ho_print_init_end($SCRIPT_NAME); ho_print("Use /MKILL HELP for help."); # --------------------------------------------------------------------- sub print_help { ho_print_help('head', $SCRIPT_NAME); ho_print_help('section', 'Syntax'); ho_print_help('syntax', 'MKILL [-simulation] [-ops] [-opers] <[nick!]user@host> []'); ho_print_help('syntax', 'MKILL [-simulation] -takeover '); ho_print_help('section', 'Description'); ho_print_help( "Mass kills all users in this channel matching the given hostmask. ". "By default only non-opped users are killed, but if ". "you specify the -ops flag, ops are killed as well.". "Opers are NOT killed by this command. BE CAREFUL if you want ". "to MKILL *\@*; make sure you do a /WHO first because the internal ". "status list might not be up to date with the actual status.\n" ); }