/var/www/www.irssi.org-old/scripts/html/autorealname.pl


   1 # Print realname of everyone who join to channels
   2 # for irssi 0.7.99 by Timo Sirainen
   3 
   4 use Irssi 20011207;
   5 use strict;
   6 use 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 
  50 Irssi::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 
  56 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)
  57 my $whois_abort_seconds = 10; # wait for 10 secs when there's been too many joins
  58 my $debug = 0;
  59 
  60 my %servers;
  61 
  62 my %whois_waiting;
  63 my %whois_queue;
  64 my %aborted;
  65 my %chan_list;
  66 
  67 sub 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 
  77 sub sig_disconnected {
  78   my $server = shift;
  79   delete $servers{$server->{tag}};
  80 }
  81 
  82 sub 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 
 167 sub 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 
 187 sub 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 
 226 sub 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 
 256 sub 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 
 264 foreach my $server (Irssi::servers()) {
 265   sig_connected($server);
 266 }
 267 
 268 sub 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 
 292 Irssi::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 });