diff options
Diffstat (limited to 'scripts/bansearch.pl')
-rw-r--r-- | scripts/bansearch.pl | 421 |
1 files changed, 421 insertions, 0 deletions
diff --git a/scripts/bansearch.pl b/scripts/bansearch.pl new file mode 100644 index 0000000..cc961ad --- /dev/null +++ b/scripts/bansearch.pl @@ -0,0 +1,421 @@ +#!/usr/bin/perl + +use strict; +use Irssi; +use Irssi::Irc; +use vars qw($VERSION %IRSSI); + +$VERSION = "1.3"; +%IRSSI = ( + authors => 'Nathan Handler, Joseph Price', + contact => 'nathan.handler@gmail.com, pricechild@ubuntu.com', + name => 'bansearch', + description => 'Searches for bans, quiets, and channel modes affecting a user', + license => 'GPLv3+', +); + +my($channel,$person,$nick,$user,$host,$real,$account,$string,$issues,$running,@jchannels,@jchannelstocheck,$debug); + +$running=0; + +sub bansearch { + my($data,$server,$witem) = @_; + + if($running) { + Irssi::print("bansearch is already running."); + } + + $running=1; + @jchannels=(); + @jchannelstocheck=(); + + #Clear variables and register redirects + &reset(); + $debug = Irssi::settings_get_bool('bansearch_debug'); + + #Split command arguments into a nick and a channel separated by a space + ($person,$channel)=split(/ /, $data, 2); + + #If no channel is specified, use the current window if it is a channel + if($channel!~m/^#/ && $person!~m/^\s*$/ && $witem->{type} eq "CHANNEL") { + $channel=$witem->{name}; + } + + #Stop the script and display usage information if they did not specify a person or if we can't find a channel to use + if($channel!~m/^#/ || $person=~m/^\s*$/) { + Irssi::active_win()->print("\x02Usage\x02: /bansearch nick [#channel]"); + $running=0; + return; + } + + #Print the name of the channel we are running on + Irssi::active_win()->print("\x02Channel\x02: $channel"); + + #Perform a /who <user> %uhnar + $server->redirect_event('who',1, '', 0, undef, + { + 'event 352' => 'redir rpl_whoreply', + 'event 354' => 'redir rpl_whospcrpl', + 'event 315' => 'redir rpl_endofwho', + 'event 401' => 'redir err_nosuchnick', + '' => 'event empty', + } + ); + $server->send_raw("WHO $person %uhnar"); +} +#Irssi::signal_add('event empty', 'EMPTY'); +Irssi::signal_add('redir rpl_whoreply', 'RPL_WHOREPLY'); +Irssi::signal_add('redir rpl_whospcrpl', 'RPL_WHOSPCRPL'); +Irssi::signal_add('redir rpl_endofwho', 'RPL_ENDOFWHO'); +Irssi::signal_add('redir err_nosuchnick', 'ERR_NOSUCHNICK'); +Irssi::signal_add('redir err_nosuchchannel', 'ERR_NOSUCHCHANNEL'); +Irssi::signal_add('redir rpl_banlist', sub { my($server,$data) = @_; RPL_BANLIST($server, "Ban $data"); }); +Irssi::signal_add('redir rpl_endofbanlist', sub { my($server,$data) = @_; RPL_ENDOFBANLIST($server, "Ban $data"); }); +Irssi::signal_add('redir rpl_quietlist', sub { my($server,$data) = @_; RPL_BANLIST($server, "Quiet $data"); }); +Irssi::signal_add('redir rpl_endofquietlist', sub { my($server,$data) = @_; RPL_ENDOFBANLIST($server, "Quiet $data"); }); +Irssi::signal_add('redir rpl_channelmodeis', 'RPL_CHANNELMODEIS'); + +sub EMPTY { + my($server, $data) = @_; + + return if(!$running); + + Irssi::print("\x02EMPTY\x02: $data"); +} + +sub RPL_BANLIST { + my($server, $data) = @_; + + return if(!$running); + + my($type, $mask, $setby, $banchannel, $jchannel); + if($data=~m/^Ban/) { + ($type, undef, $banchannel, $mask, $setby, undef) = split(/ /, $data, 6); + } + elsif($data=~m/^Quiet/) { + ($type, undef, $banchannel, undef, $mask, $setby, undef) = split(/ /, $data, 7); + } + my $maskreg = $mask; + $maskreg=~s/\$\#.*$//; #Support matching ban-forwards + $maskreg=~s/\./\\./g; + $maskreg=~s/\//\\\//g; + $maskreg=~s/\@/\\@/g; + $maskreg=~s/\[/\\[/g; + $maskreg=~s/\]/\\]/g; + $maskreg=~s/\|/\\|/g; + $maskreg=~s/\?/\./g; + $maskreg=~s/\*/\.\*\?/g; + + #We only want to display who set the ban/quiet if it is listed as a person + if($setby!~m/!/) { + $setby=''; + } + else { + $setby=" (Set by $setby)"; + } + + if($maskreg=~m/^\$/) { #extban + # account + if($maskreg=~m/^\$a:(.*?)$/i) { + if($account=~m/^$1$/i && $account!~m/^0$/) { + Irssi::active_win()->print("$type against \x02$mask\x02 in $banchannel matches $account" . $setby); + $issues++; + } + else { + Irssi::active_win()->print("$type against \x02$mask\x02 in $banchannel does NOT match $account" . $setby) if $debug; + } + } + # cannot join other channel + if($channel == $banchannel) { + if($maskreg=~m/^\$j:(.*?)$/i) { + $jchannel = $1; + if(!(grep {$jchannel eq $_} @jchannels)) { + push(@jchannels, $jchannel); + push(@jchannelstocheck, $jchannel); + Irssi::active_win()->print("Following bans in " + . $jchannel . " will " . $type . " " . $person . " in " . $channel . $setby); + } + } + } + # any logged-in user + if($maskreg=~m/^\$a$/i) { + if($account!~m/^0$/) { + Irssi::active_win()->print( + "$type against \x02$mask\x02 in $banchannel matches identified user" . $setby); + $issues++; + } + else { + Irssi::active_win()->print("$type against \x02$mask\x02 in $banchannel does NOT match unidentified user" . $setby) if $debug; + } + } + # any unidentified user + if($maskreg=~m/^\$\~a$/i) { + if($account=~m/^0$/) { + Irssi::active_win()->print( + "$type against \x02$mask\x02 in $banchannel matches unidentified user" . $setby); + $issues++; + } + else { + Irssi::active_win()->print("$type against \x02$mask\x02 in $banchannel does NOT match identified user" . $setby) if $debug; + } + } + # ircname + if($maskreg=~m/^\$r:(.*?)$/i) { + if($real=~m/^$1$/i) { + Irssi::active_win()->print( + "$type against \x02$mask\x02 in $banchannel matches real name of $real" . $setby); + $issues++; + } + else { + Irssi::active_win()->print("$type against \x02$mask\x02 in $banchannel does NOT match real name of $real" . $setby) if $debug; + } + } + # full match + if($maskreg=~m/^\$x:(.*?)$/i) { + my $full = "$nick!$user\@$host\#$real"; + if($full=~m/^$1$/i) { + Irssi::active_win()->print( + "$type against \x02$mask\x02 in $banchannel matches $full" . $setby); + $issues++; + } + else { + Irssi::active_win()->print("$type against \x02$mask\x02 in $banchannel does NOT match $full" . $setby) if $debug; + } + } + } + else { #Normal Ban + if($string=~m/^$maskreg$/i) { + Irssi::active_win()->print("$type against \x02$mask\x02 in $banchannel matches $string" . $setby); + $issues++; + } + else { + Irssi::active_win()->print("$type against \x02$mask\x02 in $banchannel does NOT match $string" . $setby) if $debug; + } + } +} + +sub RPL_ENDOFBANLIST { + my($server, $data) = @_; + + return if(!$running); + +# Irssi::active_win()->print("End of Ban List"); + if($data=~m/^Ban/) { + $server->redirect_event('mode q',1, $channel, 0, undef, + { + 'event 728' => 'redir rpl_quietlist', + 'event 729' => 'redir rpl_endofquietlist', + '' => 'event empty', + } + ); + $server->send_raw("MODE $channel q"); + } + elsif($data=~m/^Quiet/) { + if (@jchannelstocheck) { + my $nextchannel = pop(@jchannelstocheck); + $server->redirect_event('mode b',1, $nextchannel, 0, undef, + { + 'event 367' => 'redir rpl_banlist', + 'event 368' => 'redir rpl_endofbanlist', + 'event 403' => 'redir err_nosuchchannel', + '' => 'event empty', + } + ); + $server->send_raw("MODE $nextchannel b"); + } else { + $server->redirect_event('mode channel',1, $channel, 0, undef, + { + 'event 324' => 'redir rpl_channelmodeis', + '' => 'event empty', + } + ); + $server->send_raw("MODE $channel"); + } + } +} + +sub RPL_WHOREPLY { + my($server, $data) = @_; + + return if(!$running); + + # 0 1 2 3 4 5 6 7 8 + # bw2 * ~pi rpi1.my irc.example.net rpi1 H :0 real name + (undef, undef, $user, $host, undef, $nick, undef, undef, $real) = split(/ /, $data,9); + $account=''; + $real=~s/^://; + Irssi::active_win()->print("\x02User\x02: $nick [$account] ($real) $user\@$host"); +} + +sub RPL_WHOSPCRPL { + my($server, $data) = @_; + + return if(!$running); + + # $server->send_raw("WHO $person %uhnar"); + # 0 1 2 3 4 5 + # bw2 ~bw1 irc.example.net bw1 bw2 :real name + (undef, $user, $host, $nick, $account, $real) = split(/ /, $data,6); + $real=~s/^://; + Irssi::active_win()->print("\x02User\x02: $nick [$account] ($real) $user\@$host"); +} + +sub RPL_ENDOFWHO { + my($server, $data) = @_; + + return if(!$running); + + if($nick=~m/^$/ && $user=~m/^$/ && $host=~m/^$/) { + Irssi::active_win()->print("$person is currently offline."); + return; + } + $string="$nick!$user\@$host"; + $server->redirect_event('mode b',1, $channel, 0, undef, + { + 'event 367' => 'redir rpl_banlist', + 'event 368' => 'redir rpl_endofbanlist', + 'event 403' => 'redir err_nosuchchannel', + '' => 'event empty', + } + ); + $server->send_raw("MODE $channel b"); +} + +sub ERR_NOSUCHNICK { + my($server, $data) = @_; + + return if(!$running); + + Irssi::active_win()->print("$person is currently offline."); + $running=0; +} + +sub ERR_NOSUCHCHANNEL { + my($server, $data) = @_; + + return if(!$running); + + Irssi::active_win()->print("$channel does not exist."); + $running=0; +} + +sub RPL_CHANNELMODEIS { + my($server, $data) = @_; + + return if(!$running); + + my(undef, undef, $modes, $args) = split(/ /, $data, 4); + Irssi::active_win()->print("\x02Channel Modes\x02: $modes"); + if($modes=~m/i/) { + Irssi::active_win()->print("Channel is \x02invite-only\x02 (+i)"); + $issues++; + } + if($modes=~m/k/) { + Irssi::active_win()->print("Channel has a \x02password\x02 (+k)"); + $issues++; + } + if($modes=~m/r/) { + if($account=~m/^0$/) { + Irssi::active_win()->print("Channel is \x02blocking unidentified users\x02 (+r) and user is not identified"); + $issues++; + } + } + if($modes=~m/m/) { + if($server->channel_find("$channel")) { + my $n = $server->channel_find("$channel")->nick_find("$nick"); + if($n->{voice} == 0 && $n->{op} == 0) { + Irssi::active_win()->print("Channel is \x02moderated\x02 (+m) and user is not voiced or oped"); + $issues++; + } + } + else { + Irssi::active_win()->print("Channel is \x02moderated\x02 (+m) and user might not be voiced or oped"); + $issues++; + } + } + + if($issues == 0) { + Irssi::active_win()->print("There does not appear to be anything preventing $person from joining/talking in $channel"); + } + elsif ($issues == 1) { + Irssi::active_win()->print("There is \x02$issues issue\x02 that might be preventing $person from joining/talking in $channel"); + } + else { + Irssi::active_win()->print("There are \x02$issues issues\x02 that might be preventing $person from joining/talking in $channel"); + } + $running=0; +} + +sub reset { + + return if(!$running); + + $channel=''; + $person=''; + $nick=''; + $user=''; + $host=''; + $real=''; + $account=''; + $string=''; + $issues=0; + + ®ister_redirects(); +} + +sub register_redirects { + + return if(!$running); + + #who + Irssi::Irc::Server::redirect_register('who', 0, 0, + { "event 352" => 1, # start events + "event 354" => -1, + }, + { # stop events + "event 315" => 1, # End of Who List + "event 401" => 1, # No Such Nick + }, + undef, # optional events + ); + + #mode b + Irssi::Irc::Server::redirect_register('mode b', 0, 0, + { "event 367" => 1 }, # start events + { # stop events + "event 368" => 1, # End of channel ban list + "event 403" => 1, # no such channel + "event 442" => 1, # "you're not on that channel" + "event 479" => 1 # "Cannot join channel (illegal name)" + }, + undef, # optional events + ); + + #mode q + Irssi::Irc::Server::redirect_register('mode q', 0, 0, + { "event 728" => 1 }, # start events + { # stop events + "event 729" => 1, # End of channel quiet list + "event 403" => 1, # no such channel + "event 442" => 1, # "you're not on that channel" + "event 479" => 1, # "Cannot join channel (illegal name)" + }, + undef, # optional events + ); + + #mode channel + Irssi::Irc::Server::redirect_register('mode channel', 0, 0, undef, + { # stop events + "event 324" => 1, # MODE-reply + "event 403" => 1, # no such channel + "event 442" => 1, # "you're not on that channel" + "event 479" => 1 # "Cannot join channel (illegal name)" + }, + { "event 329" => 1 } # Channel create time + ); +} + +Irssi::command_bind('bansearch', 'bansearch'); +Irssi::settings_add_bool('bansearch', 'bansearch_debug', 0); + +# vim:set ts=8 sw=4: |