diff options
Diffstat (limited to 'scripts/autorealname.pl')
-rw-r--r-- | scripts/autorealname.pl | 304 |
1 files changed, 304 insertions, 0 deletions
diff --git a/scripts/autorealname.pl b/scripts/autorealname.pl new file mode 100644 index 0000000..33103e6 --- /dev/null +++ b/scripts/autorealname.pl @@ -0,0 +1,304 @@ +# Print realname of everyone who join to channels +# for irssi 0.7.99 by Timo Sirainen + +use Irssi 20011207; +use strict; +use vars qw($VERSION %IRSSI); +$VERSION = "0.8.7"; +%IRSSI = ( + authors => "Timo \'cras\' Sirainen, Bastian Blank", + contact => "tss\@iki.fi, waldi\@debian.org", + name => "auto realname", + description => "Print realname of everyone who join to channels", + license => "GPLv2 or later", + url => "http://irssi.org/", + changed => "2021-01-16" +); + +# v0.8.7 changes - bw1 +# - fix Can't call method "nick_find" ... line 282. +# v0.8.6 changes - Juhamatti Niemelä +# - fix join msg printing when there are multiple common channels +# v0.8.5 changes - Bastian Blank +# - really use the introduced state variable +# v0.8.4 changes - Bastian Blank +# - fix queue abort +# v0.8.3 changes - Bastian Blank +# - on queue abort print any join messages +# v0.8.2 changes - Bastian Blank +# - use channelname instead of Irssi::Irc::Channel for channelname within message on join +# v0.8.1 changes - Bastian Blank +# - print any join messages on abort +# - also remove any timeouts +# v0.8 changes - Bastian Blank +# - join message includes realname +# - add timeout +# - don't print realname for our self +# - change license because german law doesn't allow to give away the copyright +# v0.71 changes +# - a bit safer now with using "redirect last" +# v0.7 changes +# - pretty much a rewrite - shouldn't break anymore +# v0.62 changes +# - upgraded redirection to work with latest CVS irssi - lot easier +# to handle it this time :) +# v0.61 changes +# - forgot to reset %chan_list.. +# v0.6 changes +# - works now properly when a nick joins to multiple channels +# v0.5 changes +# - Use "message join" so we won't ask realname for ignored people + +Irssi::theme_register([ + 'join', '{channick_hilight $0} {chanhost_hilight $1} has joined {channel $2}', + 'join_realname', '{channick_hilight $0} ({hilight $1}) {chanhost_hilight $2} has joined {channel $3}', + 'join_realname_only', '{channick_hilight $0} is {hilight $1}', +]); + +my $whois_queue_length_before_abort = 10; # max. whois queue length before we should abort the whois queries for next few seconds (people are probably joining behind a netsplit) +my $whois_abort_seconds = 10; # wait for 10 secs when there's been too many joins +my $debug = 0; + +my %servers; + +my %whois_waiting; +my %whois_queue; +my %aborted; +my %chan_list; + +sub sig_connected { + my $server = shift; + $servers{$server->{tag}} = { + abort_time => 0, # if join event is received before this, abort + waiting => 0, # waiting reply for WHOIS request + queue => [], # whois queue + nicks => {} # nick => [ #chan1, #chan2, .. ] + }; +} + +sub sig_disconnected { + my $server = shift; + delete $servers{$server->{tag}}; +} + +sub msg_join { + my ($server, $channame, $nick, $host) = @_; + $channame =~ s/^://; + my $rec = $servers{$server->{tag}}; + + # don't display realname for our self + return if ($nick eq $server->{nick}); + + # don't whois people who netjoin back + return if ($server->netsplit_find($nick, $host)); + + return if (time < $rec->{abort_time}); + $rec->{abort_time} = 0; + + Irssi::signal_stop(); + + # check if the nick is already found from another channel + { + my $ret = 0; + foreach my $channel ($server->channels()) { + my $nickrec = $channel->nick_find($nick); + if ($nickrec && $nickrec->{realname}) { + # this user already has a known realname - use it. + $channel = $server->channel_find($channame); + $channel->printformat(MSGLEVEL_JOINS, 'join_realname', $nick, $nickrec->{realname}, $nickrec->{host}, $channel->{name}); + $channel->print("autorealname: already found: $nick", MSGLEVEL_CLIENTCRAP) if $debug; + $ret = 1; + last; + } + } + + return if ($ret); + } + + # save channel to nick specific hash so we can later check which channels + # it needs to print the realname + + if ($rec->{nicks}->{$nick}) { + # don't send the WHOIS again if nick is already in queue + push @{$rec->{nicks}->{$nick}->{chans_join}}, $channame; + push @{$rec->{nicks}->{$nick}->{chans_realname}}, $channame; + $rec->{nicks}->{$nick}->{state} = 0; + my $channel = $server->channel_find($channame); + $channel->print("autorealname: already in queue: $nick", MSGLEVEL_CLIENTCRAP) if $debug; + } + else { + $rec->{nicks}->{$nick} = {}; + $rec->{nicks}->{$nick}->{chans_join} = [$channame]; + $rec->{nicks}->{$nick}->{chans_realname} = [$channame]; + $rec->{nicks}->{$nick}->{state} = 0; + + # add the nick to queue + push @{$rec->{queue}}, $nick; + + # timeout + $rec->{nicks}->{$nick}->{timeout} = Irssi::timeout_add(1000, \&timeout_whois, [$server, $nick]); + my $channel = $server->channel_find($channame); + $channel->print("autorealname: add to queue: $nick", MSGLEVEL_CLIENTCRAP) if $debug; + } + + if (scalar @{$rec->{queue}} >= $whois_queue_length_before_abort) { + # too many whois requests in queue, abort + foreach $nick (@{$rec->{queue}}) { + foreach my $channel (@{$rec->{nicks}->{$nick}->{chans_join}}) { + my $chanrec = $server->channel_find($channel); + my $nickrec = $chanrec->nick_find($nick); + if ($chanrec && $nickrec) { + $chanrec->printformat(MSGLEVEL_JOINS, 'join', $nick, $nickrec->{host}, $channel); + $chanrec->print("autorealname: queue abort: $nick", MSGLEVEL_CLIENTCRAP) if $debug; + } + } + Irssi::timeout_remove($rec->{nicks}->{$nick}->{timeout}) if (!($rec->{nicks}->{$nick}->{state} & 2)); + delete $rec->{nicks}->{$nick}; + } + $rec->{queue} = []; + $rec->{abort_time} = time+$whois_abort_seconds; + return; + } + + # waiting for WHOIS reply.. + return if $rec->{waiting}; + + request_whois($server, $rec); +} + +sub request_whois { + my ($server, $rec) = @_; + return if (scalar @{$rec->{queue}} == 0); + + my @whois_nicks = splice(@{$rec->{queue}}, 0, $server->{max_whois_in_cmd}); + my $whois_query = join(',', @whois_nicks); + + # ignore all whois replies except the first line of the WHOIS reply + my $redir_arg = $whois_query.' '.join(' ', @whois_nicks); + $server->redirect_event("whois", 1, $redir_arg, 0, + "redir autorealname_whois_last", { + "event 311" => "redir autorealname_whois", + "event 401" => "redir autorealname_whois_unknown", + "redirect last" => "redir autorealname_whois_last", + "" => "event empty" }); + + $server->send_raw("WHOIS :$whois_query"); + $rec->{waiting} = 1; +} + +sub event_whois { + my ($server, $data) = @_; + my ($num, $nick, $user, $host, $empty, $realname) = split(/ +/, $data, 6); + $realname =~ s/^://; + my $rec = $servers{$server->{tag}}; + + return if not $rec->{nicks}->{$nick}; + + $rec->{nicks}->{$nick}->{state} |= 1; + + if (!($rec->{nicks}->{$nick}->{state} & 2)) { + Irssi::timeout_remove($rec->{nicks}->{$nick}->{timeout}); + foreach my $channel (@{$rec->{nicks}->{$nick}->{chans_join}}) { + my $chanrec = $server->channel_find($channel); + my $nickrec = $chanrec->nick_find($nick); + if ($chanrec && $nickrec) { + $chanrec->printformat(MSGLEVEL_JOINS, 'join_realname', $nick, $realname, $nickrec->{host}, $channel); + $chanrec->print("autorealname: got whois: $nick, state: ".$rec->{nicks}->{$nick}->{state}, MSGLEVEL_CLIENTCRAP) if $debug; + } + } + $rec->{nicks}->{$nick}->{chans_join} = []; + $rec->{nicks}->{$nick}->{chans_realname} = []; + $rec->{nicks}->{$nick}->{state} |= 2; + } + else { + foreach my $channel (@{$rec->{nicks}->{$nick}->{chans_realname}}) { + my $chanrec = $server->channel_find($channel); + next unless (defined $chanrec); + my $nickrec = $chanrec->nick_find($nick); + if ($chanrec && $nickrec) { + $chanrec->printformat(MSGLEVEL_JOINS, 'join_realname_only', $nick, $realname); + $chanrec->print("autorealname: got whois: $nick, state: ".$rec->{nicks}->{$nick}->{state}, MSGLEVEL_CLIENTCRAP) if $debug; + } + } + $rec->{nicks}->{$nick}->{chans_realname} = []; + } + + delete $rec->{nicks}->{$nick} if ($rec->{nicks}->{$nick}->{state} == 3); +} + +sub event_whois_unknown { + my ($server, $data) = @_; + my ($temp, $nick) = split(" ", $data); + my $rec = $servers{$server->{tag}}; + + return if not $rec->{nicks}->{$nick}; + + $rec->{nicks}->{$nick}->{state} |= 1; + + if (!($rec->{nicks}->{$nick}->{state} & 2)) { + Irssi::timeout_remove($rec->{nicks}->{$nick}->{timeout}); + foreach my $channel (@{$rec->{nicks}->{$nick}->{chans_join}}) { + my $chanrec = $server->channel_find($channel); + my $nickrec = $chanrec->nick_find($nick); + if ($chanrec && $nickrec) { + $chanrec->printformat(MSGLEVEL_JOINS, 'join', $nick, $nickrec->{host}, $channel); + $chanrec->print("autorealname: got unknown whois: $nick", MSGLEVEL_CLIENTCRAP) if $debug; + } + } + $rec->{nicks}->{$nick}->{chans_join} = []; + } else { + foreach my $channel (@{$rec->{nicks}->{$nick}->{chans_join}}) { + my $chanrec = $server->channel_find($channel); + $chanrec->print("autorealname: got unknown whois (already considered): $nick", MSGLEVEL_CLIENTCRAP) if $debug; + } + } + + delete $rec->{nicks}->{$nick} if ($rec->{nicks}->{$nick}->{state} == 3); +} + +sub event_whois_last { + my $server = shift; + my $rec = $servers{$server->{tag}}; + + $rec->{waiting} = 0; + request_whois($server, $rec); +} + +foreach my $server (Irssi::servers()) { + sig_connected($server); +} + +sub timeout_whois { + my $server = shift @{$_[0]}; + my $nick = shift @{$_[0]}; + + my $rec = $servers{$server->{tag}}; + + return if not $rec->{nicks}->{$nick}; + + Irssi::timeout_remove($rec->{nicks}->{$nick}->{timeout}); + $rec->{nicks}->{$nick}->{state} |= 2; + + my @channels = @{$rec->{nicks}->{$nick}->{chans_join}}; + foreach my $channel (@channels) { + my $chanrec = $server->channel_find($channel); + next unless (defined $chanrec); + my $nickrec = $chanrec->nick_find($nick); + if ($nickrec && $chanrec) { + $chanrec->printformat(MSGLEVEL_JOINS, 'join', $nick, $nickrec->{host}, $channel); + $chanrec->print("autorealname: timeout: $nick, state: ".$rec->{nicks}->{$nick}->{state}, MSGLEVEL_CLIENTCRAP) if $debug; + } + } + + $rec->{nicks}->{$nick}->{chans_join} = []; +} + +Irssi::signal_add( { + 'server connected' => \&sig_connected, + 'server disconnected' => \&sig_disconnected, + 'message join' => \&msg_join, + 'redir autorealname_whois' => \&event_whois, + 'redir autorealname_whois_unknown' => \&event_whois_unknown, + 'redir autorealname_whois_last' => \&event_whois_last }); + +# vim:set sw=2 ts=8 et: |