1############################################################################### 2# 3# Shows WHOIS: info including realname and channel names on joins to 4# channels. 5# 6# This script is based on the autorealname script, and shares a little 7# code and many ideas with that script. I use the same globals as they do, 8# but with totally different fields because their structure was not really 9# easy to adapt to a situation where more info is used on one query. 10# 11# Rewrote all that code, except for parts of request_whois and some init code 12# 13# I would like to thank Timo 'cras' Sirainen and Bastian Blank for writing 14# the autorealname script. It was a good example. 15# 16# The script contains very simple flood protection in the form that it will 17# not allow for more then $max_queued_requests per server at one time to be 18# running. It tries to be smart about netsplits, so this should be okay. 19# We have a 5-second timeout to make sure we really don't flood, ans also to 20# make sure that we don't wait indefinitely for answers that won't come. 21# 22# Themes: 23# You can change the way the WHOIS messages look using the /format command, 24# For example: 25# /FORMAT ji_whois_success %GWHOIS:%n {channick_hilight $0} \ 26# is "{hilight $1}"%n on {channel $2} 27# 28# Will add a green WHOIS: to the line to make it stand out, save your 29# formatting in irssi using '/SAVE -formats' 30# 31# Add 'server: "{hilight $3}"' to the format string to also print the 32# server name (Thanks to Svein Skogen for suggesting this) 33# 34# Add 'flags: "{hilight $4}"' to the format string to also print 35# some additional flags for the user. These flags are tailored for 36# some unknown irc network but also work quite well on IRCNet and EFNet 37# after the 'idle' modifications I added to them. Thanks to 38# Francesco Rolando for providing me with the initial patch. 39# 40# Commands (/JOININFO ...) 41# INFO - Show info on and contents of the current cache of this script 42# GC - Manually run the garbage collector once 43# FORCE - Fake join of a nick to a chan (/JOININFO FORCE ichiban) use with 44# care. Useful for testing theme changes, timeouts and the garbage 45# collector on a quiet day or network. Will ignore your own nick. 46# HELP - Shows help 47# 48# Settings 49# /SET whois_expire_time # time to expire one saves record 50# # until this age has been reched no 51# # new WHOISs will be put on the server 52# 53# /SET whois_max_requests # max concurrent requests per server 54# # flood protection, keep low 55# 56# /SET whois_timeout_ms # timeout after which a whois is lost (ms) 57# # (default: 5000) 58# 59# /SET whois_gc_interval_ms # run gc ever x MS (default: 300000) 60# # Requires script reload when changed. 61# 62# /SET whois_debug # 0 = show no debug info, 1 = debug info 63# 64# /SET whois_printing_level # Level at which all non-debug output is 65# # printed, influences logging and IGNORE 66# # (default: JOINS) 67# 68# ChangeLog: 69# - Tue Jul 15 2003, pbijdens 70# Initial release version 0.5.1 71# - Thu Jul 17 2003, pbijdens 72# Version 0.5.2 73# Added garbage collection for the stored info. 74# Added /AWINFO and /AWGC commands to show info and to run the garbage 75# collector manually respectively 76# Added timeout for the putserv WHOIS making sure we do not record too many 77# jobs as BUSY. 78# - Thu Jul 17 2003, pbijdens 79# Version 0.5.3 80# Added settings (whois_...) to the irssi config so there is no need to 81# modify the script when changing them 82# - Thu Jul 17 2003, pbijdens 83# Version 0.5.5 84# Making sure the settings are reloaded when they are changed. Added a 85# signal handler for that 86# - Thu Jul 17 2003, pbijdens 87# Version 0.6.0 88# Added setting for whois_debug 89# Added theme support 90# Bugfix for servers sending 401 without 318 no need to wait for 91# timeout anymore on those 92# Added configurable printing level for the realname+channel messages. 93# use /SET whois_printing_level 94# Added /AWFORCE command (see above) 95# - Mon Jul 28 2003, pbijdens 96# Version 0.6.1 97# Various updates and bug fixes 98# Changed awforce command to strip spaces 99# - Wed Aug 13 2003, pbijdens 100# Version 0.7.0 101# Fixed typo in comment line 102# Changed /AW* commands to be /JOININFO <subcommand> and added a 103# /JOININFO HELP command. Renamed some subs to make their purpose 104# more clear. 105# - Wed Feb 2 2004, pbijdens 106# Added features for filtering channels from the list, and adding 107# support for hilighting channels in colors. 108# - Mon Mar 8 2004, pbijdens 109# Fixed bug where also on SILCNET the WHOIS queries would be run, now 110# this service is restricted to IRC networks. Thanks to Tony den Haan 111# for supplying this patch. 112# - Mon Mar 8 2004, pbijdens 113# Added support for printing the servername also in the output for those 114# who want to see it. Thanks to Svein Skogen for suggesting this and 115# sending me a patch. 116# NOTE: Requires you to add {hilight $3} to your format string manually. 117# By default the information is not diplayed. 118# - Mon Mar 8 2004, pbijdens 119# Added support for additional flags to the WHOIS output. This is stuff 120# like IrcOP, Away, Idle and more. Thanks to Francesco Rolando for 121# providing the additional patch, which I modified. 122# NOTE: Requires you to add {hilight $4} to your format string manually. 123# By default the information is not diplayed. 124# - Tue Mar 1 2005, pbijdens 125# Updated the script for compliance with a wider range of servers, 126# and removed some functionality that generally did not work, or break 127# on some servers. Been runing on 4 networks now with these patches for 128# many months, declaring stable and releasing 1.0. 129# 130################################################################################ 131 132use Irssi 20011207; 133use strict; 134use vars qw($VERSION %IRSSI); 135use integer; 136 137################################################################################ 138 139$VERSION = "1.0.0"; 140%IRSSI = ( 141 authors => "Pieter-Bas IJdens", 142 contact => "irssi-scripts\@nospam.mi4.org.uk", 143 name => "joininfo", 144 description => "Reports WHOIS information and channel list for those who join a channel", 145 license => "GPLv2 or later", 146 url => "http://pieter-bas.ijdens.com/irssi/", 147 changed => "2005-03-10" 148); 149 150################################################################################ 151 152# Note that all settings below can and should be changed with /SET, see 153# /joininfo help or /set whois 154 155# The maximum acceeptable age for a cached whois record is 60 seconds 156# after this amount of time the cache record is discareded 157my $whois_maxage = 60; 158 159# The maximum number of requests queued at a time, if the queue reaches 160# a lrger size, ignore new requets until we have space left. This could 161# happen in a netjoin preceded by a very long netsplit 162my $max_queued_requests = 7; 163 164# Timeout after which a whois request is assumed not having been answered 165# by the server. In milliseconds 166my $whois_timeout = 5000; 167 168# Interval for the times at which GC takes place automatically. In milliseconds 169my $whois_gc_interval = 300000; 170 171# Debug poutput on or off 172my $whois_debug = 0; 173 174# Output level (the whois_printing_level_n is the numeric information for the 175# output level) 176my $whois_printing_level = "JOINS"; 177my $whois_printing_level_n; 178 179################################################################################ 180 181# Cached records per server, plus information about the amount of queued 182# reuests 183my %servers; 184 185################################################################################ 186 187# Registers the theme messages with irssi so they can be changed later by the 188# user using the /FORMAT command 189sub register_messages 190{ 191 Irssi::theme_register([ 192 'ji_whois_success', 193 '{channick_hilight $0} is "{hilight $1}"%n on {channel $2}', 194 'ji_whois_list_header', 195 'Server: {hilight $0} ($1 pending)', 196 'ji_whois_list_nick', 197 '{channick_hilight $0} is "{hilight $1}"%n on {channel $2}', 198 'ji_whois_list_status', 199 'Status: $0; Record age: $1s; Server tag: $2' 200 ]); 201} 202 203################################################################################ 204 205# Register the settings we use, and specify a DEFAULT for when Irssi 206# did not have them saved yet. Allows users to use /SET later. 207sub register_settings 208{ 209 Irssi::settings_add_int( 210 "joininfo", 211 "whois_expire_time", 212 $whois_maxage 213 ); 214 Irssi::settings_add_int( 215 "joininfo", 216 "whois_max_requests", 217 $max_queued_requests 218 ); 219 Irssi::settings_add_int( 220 "joininfo", 221 "whois_timeout_ms", 222 $whois_timeout 223 ); 224 Irssi::settings_add_int( 225 "joininfo", 226 "whois_gc_interval_ms", 227 $whois_gc_interval 228 ); 229 Irssi::settings_add_int( 230 "joininfo", 231 "whois_debug", 232 $whois_debug 233 ); 234 Irssi::settings_add_str( 235 "joininfo", 236 "whois_printing_level", 237 $whois_printing_level 238 ); 239} 240 241################################################################################ 242 243# Now (re-)read the settings, those saved in the config will be returned, 244# unless not present in which case the default will be returned 245# This function is called once on script start, and later is run as an 246# event handler when irssi notifies us of a change in settings. 247sub load_settings 248{ 249 $whois_maxage = Irssi::settings_get_int("whois_expire_time"); 250 $max_queued_requests = Irssi::settings_get_int("whois_max_requests"); 251 $whois_timeout = Irssi::settings_get_int("whois_timeout_ms"); 252 $whois_gc_interval = Irssi::settings_get_int("whois_gc_interval_ms"); 253 $whois_debug = Irssi::settings_get_int("whois_debug"); 254 $whois_printing_level = Irssi::settings_get_str("whois_printing_level"); 255 256 $whois_printing_level = uc($whois_printing_level); 257 $whois_printing_level =~ s/[^A-Z]//gi; 258 259 my($definedlvl); 260 eval("\$definedlvl = defined(MSGLEVEL_" . $whois_printing_level. ");"); 261 262 if (!$definedlvl) 263 { 264 Irssi::print( 265 "%RJOININFO:%n illegal /set whois_printing_level, see /help levels". 266 " for more informations. Assuming JOINS in stead of ". 267 "\"$whois_printing_level\"." 268 ); 269 $whois_printing_level = "JOINS"; 270 $whois_printing_level_n = MSGLEVEL_JOINS; 271 return; 272 } 273 274 eval("\$whois_printing_level_n = MSGLEVEL_" . $whois_printing_level . ";"); 275 276 if ($whois_printing_level_n == 0) 277 { 278 Irssi::print( 279 "%RJOININFO:%n illegal /set whois_printing_level, see /help levels". 280 " for more informations. Assuming JOINS in stead of ". 281 "\"$whois_printing_level\"." 282 ); 283 $whois_printing_level = "JOINS"; 284 $whois_printing_level_n = MSGLEVEL_JOINS; 285 return; 286 } 287} 288 289################################################################################ 290 291# We keep records of all nicks that ever joined a channel in our memory, 292# without ever freeing them up. This can get quite large over time, therefore 293# evere once in a while we go out and remove the garbage 294# 295# Now this function also corrects the pending counter in case strange things 296# happen on strange nets 297sub garbage_collector 298{ 299 my($runtime) = time(); 300 301 foreach my $tag (keys(%servers)) 302 { 303 my($busy) = 0; 304 my($rec) = $servers{$tag}; 305 306 foreach my $nick (keys %{$rec->{nicks}}) 307 { 308 my($age) = $runtime - $rec->{nicks}->{$nick}->{record_time}; 309 310 if ($rec->{nicks}->{$nick}->{busy}) 311 { 312 # Re-calculate the number of pending requests 313 $busy = $busy + 1; 314 315 # we can safely delete it because 600 seconds should have 316 # caused a good oldfashioned ping timeout anyway 317 # if the server is not still going to respond after 10 318 # minutes we can crash for all I care 319 if ($age > 600) 320 { 321 Irssi::print( 322 "%RWHOIS:%n Giving up on %c$nick%n, because 600 " . 323 "seconds have passed since we first asked %c$tag%n.%N" 324 ) if ($whois_debug); 325 326 # We have one request less to process now 327 $busy = $busy - 1; 328 329 # Drop the request completely and forget all about this 330 # nick 331 delete $rec->{nicks}->{$nick}; 332 } 333 } 334 elsif ($age >= 2 * $whois_maxage) 335 { 336 delete $rec->{nicks}->{$nick}; 337 } 338 339 $rec->{processing} = $busy; 340 } 341 } 342} 343 344################################################################################ 345 346# This is a very simple job to warp the call to the garbage collector. Used to 347# be self-scheduling, but irssi happily does that for us 348# 349# Pointless function, waste of memory, need one of those in every good 350# program, here is mine. 351sub aw_gc_scheduler 352{ 353 garbage_collector(); 354} 355 356################################################################################ 357 358# Show information about the autowhois stuff and about who we still know 359# Basically displays the cache contents. Some stuff may still be in the cache 360# though it is already outdated, The barbage collector will take care of 361# those entries 362sub cmd_joininfo_info 363{ 364 my($runtime) = time(); 365 366 foreach my $tag (keys(%servers)) 367 { 368 my($rec) = $servers{$tag}; 369 370 Irssi::printformat( 371 MSGLEVEL_CRAP, 372 'ji_whois_list_header', 373 $tag, 374 $rec->{processing} 375 ); 376 377 foreach my $nick (keys %{$rec->{nicks}}) 378 { 379 my($age) = $runtime - $rec->{nicks}->{$nick}->{record_time}; 380 my($status) = "OK"; 381 382 if ($rec->{nicks}->{$nick}->{busy}) 383 { 384 $status = "BUSY"; 385 } 386 elsif ($rec->{nicks}->{$nick}->{aborted}) 387 { 388 $status = "ABORTED"; 389 390 if ($rec->{nicks}->{$nick}->{known}) 391 { 392 $status = $status . " but KNOWN"; 393 } 394 } 395 else 396 { 397 $status = "COMPLETE"; 398 } 399 400 Irssi::printformat( 401 MSGLEVEL_CRAP, 402 'ji_whois_list_nick', 403 $nick, 404 $rec->{nicks}->{$nick}->{realname}, 405 $rec->{nicks}->{$nick}->{channels}, 406 $rec->{nicks}->{$nick}->{server}, 407 $rec->{nicks}->{$nick}->{flags} 408 ); 409 Irssi::printformat( 410 MSGLEVEL_CRAP, 411 'ji_whois_list_status', 412 $status, 413 $age, 414 $tag 415 ); 416 } 417 } 418} 419 420################################################################################ 421 422# A timeout is put for this function just after the WHOIS has been sent to 423# the server. When the server does not reply, then we will mark the action as 424# aborted. If a reply still ariives later (due to lag) that is not a problem 425# as it will simply be reported then. The only thing this function makes sure 426# of is that the system is not marked busy anymore so other WHOIS requests 427# can go through 428sub server_whois_timeout 429{ 430 my ($server, $nick) = @{$_[0]}; 431 my $rec = $servers{$server->{tag}}; 432 433 if ((defined($rec->{nicks}->{$nick})) 434 && ($rec->{nicks}->{$nick}->{busy} == 1) 435 ) 436 { 437 $rec->{nicks}->{$nick}->{aborted} = 1; 438 $rec->{nicks}->{$nick}->{busy} = 0; 439 440 $rec->{processing} = $rec->{processing} - 1; 441 442 Irssi::print( 443 "%RWHOIS:%n whois timeout for nick %C$nick%n ". 444 "(still running $rec->{processing} requests)" 445 ) if ($whois_debug); 446 } 447 448 # Run once, so we remove this job 449 Irssi::timeout_remove($rec->{nicks}->{$nick}->{timeout_job}); 450} 451 452################################################################################ 453 454# Put a whois request on the server (for one nick only) if and only if the 455# number of outstanding rrequests on that server is not too high 456# 457# Also installs an event handler for the next related SHOIS event that the 458# server throws at us 459sub request_whois 460{ 461 my ($server, $nick) = @_; 462 my $rec = $servers{$server->{tag}}; 463 464 return if $server->{chat_type} ne "IRC"; 465 466 if ($rec->{processing} > $max_queued_requests) 467 { 468 Irssi::print( 469 "%RWHOIS:%n Ignoring WHOIS request for %C$nick%n (too busy)%N" 470 ) if ($whois_debug); 471 record_reset($server, $nick); 472 return; 473 } 474 475 $server->redirect_event( 476 "whois", 477 1, 478 $nick, 479 0, 480 "redir autowhois_default", 481 { 482 "event 311" => "redir autowhois_realname", 483 "event 319" => "redir autowhois_channels", 484 "event 312" => "redir autowhois_server", 485 "event 301" => "redir autowhois_away", 486 "event 307" => "redir autowhois_identified", 487 "event 275" => "redir autowhois_ssl", 488 "event 310" => "redir autowhois_irchelp", 489 "event 313" => "redir autowhois_ircop", 490 "event 325" => "redir autowhois_ircbot", 491 "event 317" => "redir autowhois_idle", 492# "event 263" => "redir autowhois_busy", 493 "event 318" => "redir autowhois_end", 494 "event 401" => "redir autowhois_unknown", 495 "" => "event empty" 496 } 497 ); 498 499 $rec->{processing} = $rec->{processing} + 1; 500 501 # This format requests additional information on $nick 502 # used to be: $server->send_raw("WHOIS $nick :$nick"); 503 $server->send_raw("WHOIS $nick"); 504 505 $rec->{nicks}->{$nick}->{timeout_job} = Irssi::timeout_add( 506 $whois_timeout, 507 \&server_whois_timeout, 508 [$server, $nick] 509 ); 510} 511 512################################################################################ 513 514# A whois record is built as and when server messages with info for a specific 515# user arrive. After the WHOIS END message has arrived for that user, we can 516# report the stored whois information with this function. 517sub report_stored_whois_info 518{ 519 my ($server, $nick) = @_; 520 my $rec = $servers{$server->{tag}}; 521 522 if (!defined($rec->{nicks}->{$nick})) 523 { 524 Irssi::print( 525 "%RWHOIS:%n Report called for undefined hash %C$nick%N" 526 ) if ($whois_debug); 527 return; 528 } 529 530 foreach my $channame (@{$rec->{nicks}->{$nick}->{queued_channels}}) 531 { 532 my $chanrec = $server->channel_find($channame); 533 534 if ($chanrec) 535 { 536 $rec->{nicks}->{$nick}->{flags} =~ s/[ ]{1,}$//; 537 538 $chanrec->printformat( 539 $whois_printing_level_n, 540 'ji_whois_success', 541 $nick, 542 $rec->{nicks}->{$nick}->{realname}, 543 $rec->{nicks}->{$nick}->{channels}, 544 $rec->{nicks}->{$nick}->{server}, 545 $rec->{nicks}->{$nick}->{flags} 546 ); 547 } 548 else 549 { 550 Irssi::print( 551 "%RWHOIS:%n chanrec not found for %W$channame%n :-(%N" 552 ) if ($whois_debug); 553 } 554 } 555 556 $rec->{nicks}->{$nick}->{queued_channels} = []; 557} 558 559################################################################################ 560 561# Create an empty record for this nick on that server, we will gradually fill 562# out this record as and when we go along. 563sub record_reset 564{ 565 my ($server, $nick) = @_; 566 my $rec = $servers{$server->{tag}}; 567 568 if (defined($rec->{nicks}->{$nick})) 569 { 570 delete $rec->{nicks}->{$nick}; 571 } 572 573 $rec->{nicks}->{$nick} = 574 { 575 record_time => time(), 576 queued_channels => [], 577 realname => "(unknown)", 578 channels => "(unknown)", 579 server => "(unknown)", 580 flags => "", 581 aborted => 0, 582 busy => 0, 583 known => 0, 584 timeout_job => 0 585 }; 586} 587 588################################################################################ 589 590# Sent when a user joins a channel we are on, whic is where we check if we 591# have the user info cached, if it is still valid, and if not we put 592# a WHOIS request on the server for this user and are done. 593sub event_join 594{ 595 my ($server, $channame, $nick, $host) = @_; 596 597 return if $server->{chat_type} ne "IRC"; 598 599 $channame =~ s/^://; 600 my $rec = $servers{$server->{tag}}; 601 602 return if ($nick eq $server->{nick}); 603 604 return if ($server->netsplit_find($nick, $host)); 605 606 if (!defined($rec->{nicks}->{$nick})) 607 { 608 # If the nick has no requests joined yet, we will create a new 609 # empty record for the nick, so we can assume later it does 610 # exist 611 record_reset($server, $nick); 612 } 613 614 if (($rec->{nicks}->{$nick}->{known}) 615 && ((time() - $rec->{nicks}->{$nick}->{record_time}) <= $whois_maxage) 616 ) 617 { 618 # If we asked less than whois_maxage seconds ago for a WHOIS on this 619 # nick, we will not re-issue a request. 620 # 621 # NOTE: When a person (manually) joins multiple channels you are 622 # on, this may cause you not seeing all channels in the 623 # channel list, You can set this to something like 5 624 # seconds to reduce the probability of this happening 625 push @{$rec->{nicks}->{$nick}->{queued_channels}}, $channame; 626 627 report_stored_whois_info($server, $nick); 628 } 629 elsif ($rec->{nicks}->{$nick}->{busy} == 1) 630 { 631 # If we already issued a WHOIS request for this nick but did not 632 # receive a result yet, we just push this channel name on the 633 # list of channels that want a report when the result is known 634 push @{$rec->{nicks}->{$nick}->{queued_channels}}, $channame; 635 } 636 else 637 { 638 # Finally, we are not already processing this nick, and either 639 # we have no information for it, or the information we have is 640 # too old, so we send a WHOIS request to the server. 641 push @{$rec->{nicks}->{$nick}->{queued_channels}}, $channame; 642 643 $rec->{nicks}->{$nick}->{busy} = 1; 644 645 request_whois($server, $nick); 646 } 647} 648 649################################################################################ 650 651# Implementation of the WFORCE <nick> command. Useful for testing purposes 652# only, for example to see if the theme changes you made are correct, if the 653# timeouts are interpreted properly, and if the garbage collector works 654sub cmd_joininfo_force 655{ 656 my ($data, $server, $window) = @_; 657 $data =~ s/^[ ]{1,}//g; 658 $data =~ s/[ ]{1,}$//g; 659 660 if (!$server || !$server->{connected}) 661 { 662 Irssi::print("Not connected."); 663 return; 664 } 665 666 if ($window->{type} ne "CHANNEL") 667 { 668 Irssi::print("Not a channel window."); 669 return; 670 } 671 672 event_join($server, $window->{name}, $data, "testuser\@test.example.com"); 673} 674 675################################################################################ 676 677# Event handler for the whois realname line returned by the server. When we 678# issue a whois request, we bind an event handler for whois info for that 679# nick. 680# 681# Does nothing, except for updating the record for that nick. 682sub event_whois_realname 683{ 684 my ($server, $data) = @_; 685 my ($num, $nick, $user, $host, $empty, $realname) = split(/ +/, $data, 6); 686 $realname =~ s/^://; 687 my $rec = $servers{$server->{tag}}; 688 689 $rec->{nicks}->{$nick}->{realname} = $realname; 690} 691 692################################################################################ 693 694# Event handler for the whois channels line returned by the server. When we 695# issue a whois request, we bind an event handler for whois info for that 696# nick. 697# 698# Does nothing, except for updating the record for that nick. 699sub event_whois_channels 700{ 701 my ($server, $data) = @_; 702 my ($num, $nick, $channels) = split(/ +/, $data, 3); 703 $channels =~ s/^://; 704 my $rec = $servers{$server->{tag}}; 705 706 $channels =~ s/[ ]{1,}$//; 707 $rec->{nicks}->{$nick}->{channels} = $channels; 708} 709 710################################################################################ 711 712# Event handler for the whois server line returned by the server. When we 713# issue a whois request, we bind an event handler for whois info for that 714# nick. 715# 716# Does nothing, except for updating the record for that nick. 717# 718# NOTE: In the default report the server is not repported, it is however 719# stored in the record, so if you need it, you can simply update the 720# reporting function to show it. 721sub event_whois_server 722{ 723 my ($server, $data) = @_; 724 my ($num, $nick, $serverstr) = split(/ +/, $data, 3); 725 $serverstr =~ s/^://; 726 my $rec = $servers{$server->{tag}}; 727 728 $serverstr =~ s/ :.*$//; 729 730 $rec->{nicks}->{$nick}->{server} = $serverstr; 731} 732 733################################################################################ 734 735# This is the end of the whois request, all info available we should have 736# now, so we mark the record as know, not bust, timestamp it so we can 737# expire it later and we report back to the user on those channels waiting 738# for whois info for nick 739# 740# Note that a No Such Nick error is not always followed by a WHOIS END. 741# hyb7-based servers interpret the RFC differently from for example hyb6 742# and the IRCNet servers and will not send the WHOIS END line, but just 743# the No Such Nick error (401). 744sub event_whois_end 745{ 746 my($server, $data) = @_; 747 my ($num, $nick, $serverstr) = split(/ +/, $data, 3); 748 my $rec = $servers{$server->{tag}}; 749 750 $rec->{nicks}->{$nick}->{record_time} = time(); 751 $rec->{nicks}->{$nick}->{known} = 1; 752 $rec->{nicks}->{$nick}->{busy} = 0; 753 754 if (!$rec->{nicks}->{$nick}->{aborted}) 755 { 756 $rec->{processing} = $rec->{processing} - 1; 757 } 758 759 report_stored_whois_info($server, $nick); 760} 761 762################################################################################ 763 764# Some servers (hyb7) do not send an end of whois when the nick is 765# not known, they just send a 401 unknown message. Ircnet sends both, hyb6 766# sends both, but other servers seem to interpret the RFC differently. We 767# just treat this event_whois_unknown as a 318 tag, and mark the lookup 768# aborted (which it is in some way) 769sub event_whois_unknown 770{ 771 my($server, $data) = @_; 772 my ($num, $nick, $serverstr) = split(/ +/, $data, 3); 773 my $rec = $servers{$server->{tag}}; 774 775 # Fill out the record with some bogus information, so when we 776 # end up reporting it, we can at least see what is going on. 777 $rec->{nicks}->{$nick}->{record_time} = time(); 778 $rec->{nicks}->{$nick}->{known} = 1; 779 $rec->{nicks}->{$nick}->{busy} = 0; 780 $rec->{nicks}->{$nick}->{realname} = "(unknown)"; 781 $rec->{nicks}->{$nick}->{channels} = "(unknown)"; 782 $rec->{nicks}->{$nick}->{server} = "(unknown)"; 783 $rec->{nicks}->{$nick}->{flags} = "(unknown)"; 784 785 if (!$rec->{nicks}->{$nick}->{aborted}) 786 { 787 $rec->{processing} = $rec->{processing} - 1; 788 $rec->{nicks}->{$nick}->{aborted} = 1; 789 } 790 791 report_stored_whois_info($server, $nick); 792} 793 794################################################################################ 795 796# If the server is busy 797sub event_whois_busy 798{ 799 my($server, $data) = @_; 800 my($num, $nick, $serverstr) = split(/ +/, $data, 3); 801 my($rec) = $servers{$server->{tag}}; 802 803 Irssi::print("******************* SERVER BUSY *******************************"); 804} 805 806################################################################################ 807 808# No clue what this is for, maybe I should read the irssi documentation 809# (if it existed....) 810# 811# Judging from the debug output this function is never called. 812sub event_whois_default 813{ 814 my($server, $nick) = @_; 815 my $rec = $servers{$server->{tag}}; 816 817 Irssi::print( 818 "%RWHOIS:%n Got event_whois_default, ignoring." 819 ) if ($whois_debug); 820} 821 822################################################################################ 823 824# Some chat networks support extra falgs for their users and display those 825# in WHOIS results. The following fields allow this information to be 826# stored in the channel records and to be displayed as well. 827 828sub event_whois_away 829{ 830 my ($server, $data) = @_; 831 my $rec = $servers{$server->{tag}}; 832 my ($num, $nick, $msg) = split(/ +/, $data, 3); 833 $msg =~ s/^://; 834 $rec->{nicks}->{$nick}->{flags} = $rec->{nicks}->{$nick}->{flags}."Away "; 835} 836 837################################################################################ 838 839sub event_whois_identified 840{ 841 my ($server, $data) = @_; 842 my $rec = $servers{$server->{tag}}; 843 my ($num, $nick, $msg) = split(/ +/, $data, 3); 844 $msg =~ s/^://; 845 $rec->{nicks}->{$nick}->{flags} = $rec->{nicks}->{$nick}->{flags}."NickREG "; 846} 847 848################################################################################ 849 850sub event_whois_ssl 851{ 852 my ($server, $data) = @_; 853 my $rec = $servers{$server->{tag}}; 854 my ($num, $nick, $msg) = split(/ +/, $data, 3); 855 $msg =~ s/^://; 856 $rec->{nicks}->{$nick}->{flags} = $rec->{nicks}->{$nick}->{flags}."SSL "; 857} 858 859################################################################################ 860 861sub event_whois_irchelp 862{ 863 my ($server, $data) = @_; 864 my $rec = $servers{$server->{tag}}; 865 my ($num, $nick, $msg) = split(/ +/, $data, 3); 866 $msg =~ s/^://; 867 $rec->{nicks}->{$nick}->{flags} = $rec->{nicks}->{$nick}->{flags}."IrcHELP "; 868} 869 870################################################################################ 871 872sub event_whois_ircop 873{ 874 my ($server, $data) = @_; 875 my $rec = $servers{$server->{tag}}; 876 my ($num, $nick, $msg) = split(/ +/, $data, 3); 877 $msg =~ s/^://; 878 $rec->{nicks}->{$nick}->{flags} = $rec->{nicks}->{$nick}->{flags}."IrcOP "; 879} 880 881################################################################################ 882 883sub event_whois_ircbot 884{ 885 my ($server, $data) = @_; 886 my $rec = $servers{$server->{tag}}; 887 my ($num, $nick, $msg) = split(/ +/, $data, 3); 888 $msg =~ s/^://; 889 $rec->{nicks}->{$nick}->{flags} = $rec->{nicks}->{$nick}->{flags}."IrcBOT "; 890} 891 892################################################################################ 893 894sub number_to_timestr 895{ 896 my($number) = @_; 897 my ($result) = ""; 898 899 # Force integer 900 $number = 1 * $number; 901 902 my($days) = $number / 86400; 903 $number = $number % 86400; 904 my($hours) = $number / 3600; 905 $number = $number % 3600; 906 my($minutes) = $number / 60; 907 $number = $number % 60; 908 my($seconds) = $number; 909 910 if ($days) { $result = $result . "${days}d"; } 911 if ($hours || $result) { $result = $result . "${hours}h"; } 912 if ($minutes || $result) { $result = $result . "${minutes}m"; } 913 $result = $result . "${seconds}s"; 914 915 return $result; 916} 917 918################################################################################ 919 920sub event_whois_idle 921{ 922 my ($server, $data) = @_; 923 my $rec = $servers{$server->{tag}}; 924 my ($num, $nick, $msg) = split(/ +/, $data, 3); 925 $msg =~ s/^://; 926 927 if ($msg =~ /^([0-9]{1,}) ([0-9]{1,}) :.*$/) 928 { 929 my($idle) = 1 * $1; 930 my($signon) = 1 * $2; 931 932 $rec->{nicks}->{$nick}->{flags} = $rec->{nicks}->{$nick}->{flags} 933 . "Idle=" . number_to_timestr($idle). " "; 934 } 935 elsif ($msg =~ /^([0-9]{1,}) :.*$/) 936 { 937 my($idle) = 1 * $1; 938 939 $rec->{nicks}->{$nick}->{flags} = $rec->{nicks}->{$nick}->{flags} 940 . "Idle=" . number_to_timestr($idle). " "; 941 } 942 else 943 { 944 $rec->{nicks}->{$nick}->{flags} = $rec->{nicks}->{$nick}->{flags}."SameSRV "; 945 } 946} 947 948################################################################################ 949 950# Initializes a server record for the autowhois. Either called when a server 951# does connect to the network, or on script load for all connected servers at 952# that time 953sub event_connected 954{ 955 my($server) = @_; 956 957 $servers{$server->{tag}} = { 958 processing => 0, # waiting reply for WHOIS request 959 nicks => {} # nick => [ #chan1, #chan2, .. ] 960 }; 961} 962 963################################################################################ 964 965# Deletes a server record for the autowhois. We do this on disconnect 966sub event_disconnected 967{ 968 my($server) = @_; 969 970 delete $servers{$server->{tag}}; 971} 972 973################################################################################ 974 975# Implementation of what I call the /JOININFO umbrella command. Below 976# we bind all subcommands for this command already, so all we need to 977# do is hand off the event to irssi again so it can call the right 978# implementation function for it. 979sub cmd_joininfo 980{ 981 my ($data, $server, $item) = @_; 982 $data =~ s/\s+$//g; 983 Irssi::command_runsub ('joininfo', $data, $server, $item); 984} 985 986################################################################################ 987 988# Shows help 989sub cmd_joininfo_help 990{ 991 Irssi::print( <<EOF 992 993JOININFO FORCE <nick> 994JOININFO GC 995JOININFO INFO 996JOININFO HELP 997 998JOININFO FORCE <nick> 999 Fakes the join of a certain nick to the channel, and shows you 1000 what the WHOIS line would look like. 1001JOININFO GC 1002 Forces running the garbage collector once 1003JOININFO INFO 1004 Shows the WHOIS cache as it exists. Note that records in the cache 1005 may be outdated but not deleted yet by the garbage collector 1006JOININFO HELP 1007 This page 1008 1009Example: 1010 JOININFO FORCE ichiban 1011 1012Settings: 1013 Use /SET to change whois_expire_time, whois_max_requests, 1014 whois_timeout_ms, whois_gc_interval_ms, whois_debug, or 1015 whois_printing_level 1016 1017These settings: 1018 Use /FORMAT to change ji_whois_success, ji_whois_list_header, 1019 ji_whois_list_nick, or ji_whois_list_status 1020 1021Note: If you want to hilight certain channels in the output, just use 1022/HILIGHT -level JOINS #channel 1023 1024See also: HILIGHT 1025EOF 1026 , MSGLEVEL_CLIENTCRAP); 1027} 1028 1029################################################################################ 1030 1031# Tegister messages for /FORMAT and theme support 1032register_messages(); 1033 1034# Register settings for /SET support 1035register_settings(); 1036 1037# Load the previously stored settings from the config file, will be called 1038# again later each time the settings change 1039load_settings(); 1040 1041################################################################################ 1042 1043# Mark all currently connected servers as connected 1044foreach my $server (Irssi::servers()) 1045{ 1046 event_connected($server); 1047} 1048 1049################################################################################ 1050 1051# Add and register our signal handlers 1052Irssi::signal_add( 1053{ 'server connected' => \&event_connected, 1054 'server disconnected' => \&event_disconnected, 1055 'message join' => \&event_join, 1056 'redir autowhois_realname' => \&event_whois_realname, 1057 'redir autowhois_channels' => \&event_whois_channels, 1058 'redir autowhois_server' => \&event_whois_server, 1059 'redir autowhois_away' => \&event_whois_away, 1060 'redir autowhois_identified' => \&event_whois_identified, 1061 'redir autowhois_ssl' => \&event_whois_ssl, 1062 'redir autowhois_irchelp' => \&event_whois_irchelp, 1063 'redir autowhois_ircop' => \&event_whois_ircop, 1064 'redir autowhois_ircbot' => \&event_whois_ircbot, 1065 'redir autowhois_idle' => \&event_whois_idle, 1066 'redir autowhois_end' => \&event_whois_end, 1067 'redir autowhois_unknown' => \&event_whois_unknown, 1068 'redir autowhois_busy' => \&event_whois_busy, 1069 'setup changed' => \&load_settings } 1070); 1071 1072################################################################################ 1073 1074# Schedule the garbase collector to run every whois_gc_interval ms 1075Irssi::timeout_add( 1076 $whois_gc_interval, 1077 \&aw_gc_scheduler, 1078 0 1079); 1080 1081################################################################################ 1082 1083# OLD STYLE COMMANDS ARE DISABLED AND REPLACED BY /JOININFO WITH SUB-COMMANDS 1084# Bind the /AWFORCE, /AWGC and /AWINFO commands. Uncomment the next three lines 1085# if you would like to keep the old-style commands 1086### Irssi::command_bind("awforce", "cmd_joininfo_force"); 1087### Irssi::command_bind("awgc", "garbage_collector"); 1088### Irssi::command_bind("awinfo", "cmd_joininfo_info"); 1089 1090Irssi::command_bind("joininfo force", \&cmd_joininfo_force); 1091Irssi::command_bind("joininfo gc", \&garbage_collector); 1092Irssi::command_bind("joininfo info", \&cmd_joininfo_info); 1093Irssi::command_bind("joininfo help", \&cmd_joininfo_help); 1094Irssi::command_bind("joininfo", \&cmd_joininfo); 1095 1096################################################################################ 1097### EOF 1098