# BUGS AND IMPORTANT NOTES: # - /msg #foo,bar,#baz is unsupported and will split the lines a little too # early (but won't cutoff or destroy your messages). # # - Cutoff text is almost always caused by the user@host being too short. # # - The only time by default that irssi 'discovers' your user@host is the # first time you join a channel. Not only does this not work if you haven't # joined a channel, it doesn't ever update. Whois replies can't be trusted, # because they often lie to everyone but you; and not all servers do 001 # properly. So, we NOTICE self to get a user@host on connect, on usermode # changes (since most cloak and vhost systems cause or are caused by a # usermode change), and on /upgrade. These might not be the only ways a # user@host can change, so there's a /splitlong get command that tries to # update the user@host. use strict; use warnings; use vars qw($VERSION %IRSSI); use Irssi 20020324; $VERSION = "0.20.45"; %IRSSI = ( name => "splitlong.pl", description => "Split overlong PRIVMSGs to msgs with length allowed by ircd", url => "http://ferret.xelam.net/linux/splitlong.pl", authors => "ferret", contact => "ferret tA xelam teNtoD", origin => "original author Bjoern 'fuchs' Krombholz, bjkro\@gmx.de", licence => "Public Domain", changed => "2007-10-10", changes => "0.20.44: support /me, /msg -chatnet, aggressively get userhost" . "0.20.45: cleanup, remove 001 stuff, fix redirects", modules => "", commands => "splitlong", ); sub cmd_splitlong { my ( $cmd ) = split / /, $_[0]; if( $cmd eq 'help' ) { cmd_help( @_ ); } elsif( $cmd eq 'print' ) { cmd_print( @_ ); } elsif( $cmd eq 'get' ) { cmd_get( @_ ); } else { Irssi::print '$IRSSI{name}: for help: /splitlong help'; } } # /splitlong - print help sub cmd_help { Irssi::print "$IRSSI{name} version $VERSION"; print <<'EOT'; /set splitlong_max_length Max length of message. '0' means calculate the maximum. Default: 0 (recommended) /set splitlong_line_start /set splitlong_line_end Defaults: "... ", " ...". /splitlong get Get your user@host from the server and store it Try this if you get cutoffs and '/splitlong print' prints a wrong user@host /splitlong print Prints the script's current idea of your user@host Use '/foreach server /splitlong print' to print it for all servers EOT } # /splitlong print - print $userhosts{active server tag} sub cmd_print { my( undef, $server ) = @_; our %userhosts; print "$server->{tag}: $userhosts{$server->{tag}}"; } # /splitlong get - redo $userhosts{active server tag} sub cmd_get { my( undef, $server ) = @_; update_userhost( $server ); } # main splitting handler sub sig_command_msg { my ($cmd, $server, $winitem, $action) = @_; if( $cmd =~ s/^SPLIT_WITH_SPLITLONG// ) { # if the magic message is there we must have split it already Irssi::signal_continue( $cmd, $server, $winitem ); return; } my ( $param, $target, $data ) = $action eq 'me' ? ( '', '', $cmd ) # From /help: # MSG [-] [-channel | -nick] # ACTION [-] # note that /say does /msg * and text entry in a channel or # query window does for e.g. /msg -channel "#channel" : $cmd =~ /^((?:-\S*\s)*)(\S*\s)(.*)/; my $real_server = $server; if( $param =~ /^-(\S*)/ ) { unless( $1 eq 'nick' or $1 eq 'channel') { $real_server = Irssi::server_find_tag( $1 ); } } $real_server && $real_server->{connected} or return; # typically at this point $target eq '"#channel" '; my( $real_target ) = $target =~ /^"?(.*?)"?\s?$/; if( $real_target eq '' or $real_target eq '*' ) { # it's a /say (which is really a /msg *) or a /me # they don't make sense outside of a channel or query $winitem && $winitem->{name} or return; $real_target = $winitem->{name}; } my $maxlength = Irssi::settings_get_int( 'splitlong_max_length' ); my $lstart = Irssi::settings_get_str( 'splitlong_line_start' ); my $lend = Irssi::settings_get_str( 'splitlong_line_end' ); if ($maxlength == 0) { # :mynick!user@host PRIVMSG nick :message # 497 = 510 - length(":" . "!" . " PRIVMSG " . " :"); our %userhosts; $maxlength = 497 - length( $real_server->{nick} . $userhosts{$real_server->{tag}} . $real_target ); # my $header = ":$real_server->{nick}!$userhosts{$real_server->{tag}} PRIVMSG $real_target :"; # Irssi.print "$IRSSI{name}: header: '$header' length: ", length( $header ); } # 9 = length( "\01ACTION " . $msg . "\01" ) - length( $msg ); $action eq 'me' || $action eq 'action' and $maxlength -= 9; my $maxlength2 = $maxlength - length( $lend ); # Irssi.print "$IRSSI{name}: maxlength: $maxlength"; if (length( $data ) > ( $maxlength ) ) { my ( $pos, $datachunk ); while ( length( $data ) > $maxlength2 ) { $pos = rindex( $data, " ", $maxlength2 ); # if the rightmost space ($pos) is only 60 chars in then split in # the middle of a word instead $datachunk = substr( $data, 0, $pos < 60 ? $maxlength2 : $pos ) . $lend; # this script WILL recapture this signal, so we 'mark' it Irssi::signal_emit( "command $action", 'SPLIT_WITH_SPLITLONG' . $param . $target . $datachunk, $server, $winitem ); $data = $lstart . substr( $data, $pos < 60 ? $maxlength2 : $pos + 1 ); } Irssi::signal_continue( $param . $target . $data, $server, $winitem ); } } # fill $userhosts{$servtag} when a server is first connected # If we try to send a notice straight away, some servers don't send it # So we wait 5 seconds. It's a bit hackish, but I don't know a better way sub sig_connect { my( $server ) = @_; Irssi::timeout_add_once( 5000, 'delayed_update', $server->{tag} ); } sub delayed_update { my( $servtag ) = @_; update_userhost( Irssi::server_find_tag( $servtag ) ); } # when a /umode is received from $servtag, $userhosts{$servtag} needs redoing sub sig_thisnet { my( $server ) = @_; update_userhost( $server ); } # when an /upgrade has happened, %userhosts needs completely refilling # same with when script first loads sub sig_allnets { update_userhost( $_ ) for Irssi::servers(); } # fire off a notice to self, the reply of is caught by redir signal sub update_userhost { my( $server ) = @_; $server->{chat_type} eq 'IRC' or return; $server->redirect_event( 'SL notice', 1, ':splitlong.pl', -1, '', { 'event notice' => 'redir SL notice' } ); $server->send_raw( "NOTICE $server->{nick} :splitlong.pl - you should never see this, please report it as a bug" ); } # redir signal catcher sub sig_reply { my( $server, $cmd, $nick, $userhost ) = @_; our %userhosts; $userhosts{$server->{tag}} = $userhost; # Irssi::print "$IRSSI{name}: updated userhost for $server->{tag} to $userhost"; } Irssi::settings_add_int( 'misc', 'splitlong_max_length', 0 ); Irssi::settings_add_str( 'misc', 'splitlong_line_start', "... " ); Irssi::settings_add_str( 'misc', 'splitlong_line_end', " ..." ); Irssi::signal_add_first( 'command msg' => sub { sig_command_msg( @_, 'msg' ); } ); Irssi::signal_add_first( 'command action' => sub { sig_command_msg( @_, 'action' ); } ); Irssi::signal_add_first( 'command me' => sub { sig_command_msg( @_, 'me' ); } ); Irssi::signal_add_last( 'session restore' => \&sig_allnets ); Irssi::signal_add_last( 'user mode changed' => \&sig_thisnet ); Irssi::signal_add_last( 'server connected' => \&sig_connect ); Irssi::signal_add_first( 'redir SL notice' => \&sig_reply ); Irssi::command_bind( 'splitlong' => \&cmd_splitlong ); Irssi::command_bind( 'splitlong help' => \&cmd_help ); Irssi::command_bind( 'splitlong get' => \&cmd_get ); Irssi::command_bind( 'splitlong print' => \&cmd_print ); Irssi::Irc::Server::redirect_register( 'SL notice', 1, 5, undef, { "event notice" => 1, }, undef ); Irssi::print "$IRSSI{name} version $VERSION loaded. For help: /splitlong help"; sig_allnets(); # gets user@host for all networks