1# Print realname of everyone who join to channels 2# for irssi 0.7.99 by Timo Sirainen 3 4use Irssi 20011207; 5use strict; 6use vars qw($VERSION %IRSSI); 7$VERSION = "0.8.6"; 8%IRSSI = ( 9 authors => "Timo \'cras\' Sirainen, Bastian Blank", 10 contact => "tss\@iki.fi, waldi\@debian.org", 11 name => "auto realname", 12 description => "Print realname of everyone who join to channels", 13 license => "GPLv2 or later", 14 url => "http://irssi.org/", 15 changed => "Fri, 24 Jan 2003 15:40:22 +0100" 16); 17 18# v0.8.6 changes - Juhamatti Niemelä 19# - fix join msg printing when there are multiple common channels 20# v0.8.5 changes - Bastian Blank 21# - really use the introduced state variable 22# v0.8.4 changes - Bastian Blank 23# - fix queue abort 24# v0.8.3 changes - Bastian Blank 25# - on queue abort print any join messages 26# v0.8.2 changes - Bastian Blank 27# - use channelname instead of Irssi::Irc::Channel for channelname within message on join 28# v0.8.1 changes - Bastian Blank 29# - print any join messages on abort 30# - also remove any timeouts 31# v0.8 changes - Bastian Blank 32# - join message includes realname 33# - add timeout 34# - don't print realname for our self 35# - change license because german law doesn't allow to give away the copyright 36# v0.71 changes 37# - a bit safer now with using "redirect last" 38# v0.7 changes 39# - pretty much a rewrite - shouldn't break anymore 40# v0.62 changes 41# - upgraded redirection to work with latest CVS irssi - lot easier 42# to handle it this time :) 43# v0.61 changes 44# - forgot to reset %chan_list.. 45# v0.6 changes 46# - works now properly when a nick joins to multiple channels 47# v0.5 changes 48# - Use "message join" so we won't ask realname for ignored people 49 50Irssi::theme_register([ 51 'join', '{channick_hilight $0} {chanhost_hilight $1} has joined {channel $2}', 52 'join_realname', '{channick_hilight $0} ({hilight $1}) {chanhost_hilight $2} has joined {channel $3}', 53 'join_realname_only', '{channick_hilight $0} is {hilight $1}', 54]); 55 56my $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) 57my $whois_abort_seconds = 10; # wait for 10 secs when there's been too many joins 58my $debug = 0; 59 60my %servers; 61 62my %whois_waiting; 63my %whois_queue; 64my %aborted; 65my %chan_list; 66 67sub sig_connected { 68 my $server = shift; 69 $servers{$server->{tag}} = { 70 abort_time => 0, # if join event is received before this, abort 71 waiting => 0, # waiting reply for WHOIS request 72 queue => [], # whois queue 73 nicks => {} # nick => [ #chan1, #chan2, .. ] 74 }; 75} 76 77sub sig_disconnected { 78 my $server = shift; 79 delete $servers{$server->{tag}}; 80} 81 82sub msg_join { 83 my ($server, $channame, $nick, $host) = @_; 84 $channame =~ s/^://; 85 my $rec = $servers{$server->{tag}}; 86 87 # don't display realname for our self 88 return if ($nick eq $server->{nick}); 89 90 # don't whois people who netjoin back 91 return if ($server->netsplit_find($nick, $host)); 92 93 return if (time < $rec->{abort_time}); 94 $rec->{abort_time} = 0; 95 96 Irssi::signal_stop(); 97 98 # check if the nick is already found from another channel 99 { 100 my $ret = 0; 101 foreach my $channel ($server->channels()) { 102 my $nickrec = $channel->nick_find($nick); 103 if ($nickrec && $nickrec->{realname}) { 104 # this user already has a known realname - use it. 105 $channel = $server->channel_find($channame); 106 $channel->printformat(MSGLEVEL_JOINS, 'join_realname', $nick, $nickrec->{realname}, $nickrec->{host}, $channel->{name}); 107 $channel->print("autorealname: already found: $nick", MSGLEVEL_CLIENTCRAP) if $debug; 108 $ret = 1; 109 last; 110 } 111 } 112 113 return if ($ret); 114 } 115 116 # save channel to nick specific hash so we can later check which channels 117 # it needs to print the realname 118 119 if ($rec->{nicks}->{$nick}) { 120 # don't send the WHOIS again if nick is already in queue 121 push @{$rec->{nicks}->{$nick}->{chans_join}}, $channame; 122 push @{$rec->{nicks}->{$nick}->{chans_realname}}, $channame; 123 $rec->{nicks}->{$nick}->{state} = 0; 124 my $channel = $server->channel_find($channame); 125 $channel->print("autorealname: already in queue: $nick", MSGLEVEL_CLIENTCRAP) if $debug; 126 } 127 else { 128 $rec->{nicks}->{$nick} = {}; 129 $rec->{nicks}->{$nick}->{chans_join} = [$channame]; 130 $rec->{nicks}->{$nick}->{chans_realname} = [$channame]; 131 $rec->{nicks}->{$nick}->{state} = 0; 132 133 # add the nick to queue 134 push @{$rec->{queue}}, $nick; 135 136 # timeout 137 $rec->{nicks}->{$nick}->{timeout} = Irssi::timeout_add(1000, \&timeout_whois, [$server, $nick]); 138 my $channel = $server->channel_find($channame); 139 $channel->print("autorealname: add to queue: $nick", MSGLEVEL_CLIENTCRAP) if $debug; 140 } 141 142 if (scalar @{$rec->{queue}} >= $whois_queue_length_before_abort) { 143 # too many whois requests in queue, abort 144 foreach $nick (@{$rec->{queue}}) { 145 foreach my $channel (@{$rec->{nicks}->{$nick}->{chans_join}}) { 146 my $chanrec = $server->channel_find($channel); 147 my $nickrec = $chanrec->nick_find($nick); 148 if ($chanrec && $nickrec) { 149 $chanrec->printformat(MSGLEVEL_JOINS, 'join', $nick, $nickrec->{host}, $channel); 150 $chanrec->print("autorealname: queue abort: $nick", MSGLEVEL_CLIENTCRAP) if $debug; 151 } 152 } 153 Irssi::timeout_remove($rec->{nicks}->{$nick}->{timeout}) if (!($rec->{nicks}->{$nick}->{state} & 2)); 154 delete $rec->{nicks}->{$nick}; 155 } 156 $rec->{queue} = []; 157 $rec->{abort_time} = time+$whois_abort_seconds; 158 return; 159 } 160 161 # waiting for WHOIS reply.. 162 return if $rec->{waiting}; 163 164 request_whois($server, $rec); 165} 166 167sub request_whois { 168 my ($server, $rec) = @_; 169 return if (scalar @{$rec->{queue}} == 0); 170 171 my @whois_nicks = splice(@{$rec->{queue}}, 0, $server->{max_whois_in_cmd}); 172 my $whois_query = join(',', @whois_nicks); 173 174 # ignore all whois replies except the first line of the WHOIS reply 175 my $redir_arg = $whois_query.' '.join(' ', @whois_nicks); 176 $server->redirect_event("whois", 1, $redir_arg, 0, 177 "redir autorealname_whois_last", { 178 "event 311" => "redir autorealname_whois", 179 "event 401" => "redir autorealname_whois_unknown", 180 "redirect last" => "redir autorealname_whois_last", 181 "" => "event empty" }); 182 183 $server->send_raw("WHOIS :$whois_query"); 184 $rec->{waiting} = 1; 185} 186 187sub event_whois { 188 my ($server, $data) = @_; 189 my ($num, $nick, $user, $host, $empty, $realname) = split(/ +/, $data, 6); 190 $realname =~ s/^://; 191 my $rec = $servers{$server->{tag}}; 192 193 return if not $rec->{nicks}->{$nick}; 194 195 $rec->{nicks}->{$nick}->{state} |= 1; 196 197 if (!($rec->{nicks}->{$nick}->{state} & 2)) { 198 Irssi::timeout_remove($rec->{nicks}->{$nick}->{timeout}); 199 foreach my $channel (@{$rec->{nicks}->{$nick}->{chans_join}}) { 200 my $chanrec = $server->channel_find($channel); 201 my $nickrec = $chanrec->nick_find($nick); 202 if ($chanrec && $nickrec) { 203 $chanrec->printformat(MSGLEVEL_JOINS, 'join_realname', $nick, $realname, $nickrec->{host}, $channel); 204 $chanrec->print("autorealname: got whois: $nick, state: ".$rec->{nicks}->{$nick}->{state}, MSGLEVEL_CLIENTCRAP) if $debug; 205 } 206 } 207 $rec->{nicks}->{$nick}->{chans_join} = []; 208 $rec->{nicks}->{$nick}->{chans_realname} = []; 209 $rec->{nicks}->{$nick}->{state} |= 2; 210 } 211 else { 212 foreach my $channel (@{$rec->{nicks}->{$nick}->{chans_realname}}) { 213 my $chanrec = $server->channel_find($channel); 214 my $nickrec = $chanrec->nick_find($nick); 215 if ($chanrec && $nickrec) { 216 $chanrec->printformat(MSGLEVEL_JOINS, 'join_realname_only', $nick, $realname); 217 $chanrec->print("autorealname: got whois: $nick, state: ".$rec->{nicks}->{$nick}->{state}, MSGLEVEL_CLIENTCRAP) if $debug; 218 } 219 } 220 $rec->{nicks}->{$nick}->{chans_realname} = []; 221 } 222 223 delete $rec->{nicks}->{$nick} if ($rec->{nicks}->{$nick}->{state} == 3); 224} 225 226sub event_whois_unknown { 227 my ($server, $data) = @_; 228 my ($temp, $nick) = split(" ", $data); 229 my $rec = $servers{$server->{tag}}; 230 231 return if not $rec->{nicks}->{$nick}; 232 233 $rec->{nicks}->{$nick}->{state} |= 1; 234 235 if (!($rec->{nicks}->{$nick}->{state} & 2)) { 236 Irssi::timeout_remove($rec->{nicks}->{$nick}->{timeout}); 237 foreach my $channel (@{$rec->{nicks}->{$nick}->{chans_join}}) { 238 my $chanrec = $server->channel_find($channel); 239 my $nickrec = $chanrec->nick_find($nick); 240 if ($chanrec && $nickrec) { 241 $chanrec->printformat(MSGLEVEL_JOINS, 'join', $nick, $nickrec->{host}, $channel); 242 $chanrec->print("autorealname: got unknown whois: $nick", MSGLEVEL_CLIENTCRAP) if $debug; 243 } 244 } 245 $rec->{nicks}->{$nick}->{chans_join} = []; 246 } else { 247 foreach my $channel (@{$rec->{nicks}->{$nick}->{chans_join}}) { 248 my $chanrec = $server->channel_find($channel); 249 $chanrec->print("autorealname: got unknown whois (already considered): $nick", MSGLEVEL_CLIENTCRAP) if $debug; 250 } 251 } 252 253 delete $rec->{nicks}->{$nick} if ($rec->{nicks}->{$nick}->{state} == 3); 254} 255 256sub event_whois_last { 257 my $server = shift; 258 my $rec = $servers{$server->{tag}}; 259 260 $rec->{waiting} = 0; 261 request_whois($server, $rec); 262} 263 264foreach my $server (Irssi::servers()) { 265 sig_connected($server); 266} 267 268sub timeout_whois { 269 my $server = shift @{$_[0]}; 270 my $nick = shift @{$_[0]}; 271 272 my $rec = $servers{$server->{tag}}; 273 274 return if not $rec->{nicks}->{$nick}; 275 276 Irssi::timeout_remove($rec->{nicks}->{$nick}->{timeout}); 277 $rec->{nicks}->{$nick}->{state} |= 2; 278 279 my @channels = @{$rec->{nicks}->{$nick}->{chans_join}}; 280 foreach my $channel (@channels) { 281 my $chanrec = $server->channel_find($channel); 282 my $nickrec = $chanrec->nick_find($nick); 283 if ($nickrec && $chanrec) { 284 $chanrec->printformat(MSGLEVEL_JOINS, 'join', $nick, $nickrec->{host}, $channel); 285 $chanrec->print("autorealname: timeout: $nick, state: ".$rec->{nicks}->{$nick}->{state}, MSGLEVEL_CLIENTCRAP) if $debug; 286 } 287 } 288 289 $rec->{nicks}->{$nick}->{chans_join} = []; 290} 291 292Irssi::signal_add( { 293 'server connected' => \&sig_connected, 294 'server disconnected' => \&sig_disconnected, 295 'message join' => \&msg_join, 296 'redir autorealname_whois' => \&event_whois, 297 'redir autorealname_whois_unknown' => \&event_whois_unknown, 298 'redir autorealname_whois_last' => \&event_whois_last }); 299