use strict; use vars qw($VERSION %IRSSI); use Irssi; $VERSION = '1.00'; %IRSSI = ( authors => 'Robert Marsh', contact => 'rdmarsh2@gmail.com', name => 'multiact.pl', description => 'Makes at most one window active when a single nick joins/parts/quits/chnages names while in multiple channels', license => 'Public Domain', ); my %alt_tables; # chatnet -> alt -> real my %last_act_tables; # server tag -> nick -> time my $min_time = # Irssi::settings_get_int('displayed_action_timeout') || 30; # handles new connections to servers, runs on message 'server connected' or # at init sub sig_connected { my ($server) = @_; $alt_tables{$server->{tag}} = { load_alts($server->{tag}), }; } # handles lost or dropped connections to servers, runs on message 'server # disconnectd' # TODO: does this run on /quit? sub sig_disconnected { my ($server) = @_; Irssi::print($server->{tag}); write_alts($server->{tag}); delete $alt_tables{$server->{tag}}; } # reads alt-lists from disk sub load_alts { open ALTS, "$ENV{HOME}/.irssi/alts_".@_[0] || do {Irssi::print('failed to open file for reading');return {}}; my %alt_list; while() { my @lines = split "\n"; foreach my $line (@lines) { my ($alt_nick, $real_nick) = split ":", $line; $alt_list{$alt_nick} = $real_nick; } } close ALTS; return %alt_list; } # saves alt-lists to disk sub write_alts { my ($chatnet) = @_; my %alts = %{%alt_tables->{$chatnet}}; Irssi::print("$ENV{HOME}/.irssi/alts_".$chatnet); open ALTS, '>', "$ENV{HOME}/.irssi/alts_".$chatnet || do { Irssi::print('failed to open file for writing'); return}; foreach my $key (keys %alts) { print ALTS "$key:".$alts{$key}."\n"; Irssi::print($key); } close ALTS; } # runs on message 'message join', prints standard message in joined channel, # does not make window active sub msg_join { my ($server, $channel, $nick, $address) = @_; my $msg_level = MSGLEVEL_JOINS; $msg_level += check_timeout($server, $nick); $server->printformat($channel, $msg_level, 'join', $nick, $address, $channel); Irssi::signal_stop; } # runs on message 'message part', prints standard message in parted channel, # does not make window active sub msg_part { my ($server, $channel, $nick, $address, $reason) = @_; my $msg_level = MSGLEVEL_PARTS; $msg_level += check_timeout($server, $nick); $server->printformat($channel, $msg_level, 'part', $nick, $address, $channel, $reason); Irssi::signal_stop; } # runs on message 'message quit', prints standard message in all shared # channels, does not make windows active sub msg_quit { my ($server, $nick, $address, $reason) = @_; my $msg_level = MSGLEVEL_QUITS; my $active_window = Irssi::active_win(); my $active_item = $active_window->{active}; my $query; $msg_level += check_timeout($server, $nick); if($active_item && $active_item->{type} eq "CHANNEL" && $active_item->{server_tag} == $server->{tag} && $active_item->nick_find($nick)) { $active_item->printformat($msg_level, 'quit', $nick, $address, $reason); $msg_level = MSGLEVEL_QUITS + MSGLEVEL_NO_ACT; } $query = $server->query_find($nick); if($query) { $query->printformat($msg_level, 'quit', $nick, $address, $reason); $msg_level = MSGLEVEL_QUITS + MSGLEVEL_NO_ACT; } foreach my $channel ($server->channels()) { if($channel->nick_find($nick) && ($channel->{name} ne $active_item->{name})) { $channel->printformat($msg_level, 'quit', $nick, $address, $reason); $msg_level = MSGLEVEL_QUITS + MSGLEVEL_NO_ACT; } } Irssi::signal_stop(); } # runs on message 'message nick', prints standard message in all shared # channels, does not make window active sub msg_nick { my ($server, $newnick, $oldnick, $address) = @_; my $msg_level = MSGLEVEL_QUITS; my $active_window = Irssi::active_win(); my $active_item = $active_window->{active}; my $query; if($server->query_find($oldnick)) { $msg_level += MSGLEVEL_NO_ACT; } else { $msg_level += check_timeout($server, $newnick); } if($active_item && $active_item->{type} eq "CHANNEL" && $active_item->{server_tag} == $server->{tag} && $active_item->nick_find($newnick)) { $active_item->printformat($msg_level, 'nick_changed', $oldnick, $newnick, $address); $msg_level = MSGLEVEL_QUITS + MSGLEVEL_NO_ACT; } foreach my $channel ($server->channels()) { if($channel->nick_find($newnick) && ($channel->{name} ne $active_item->{name})) { $channel->printformat($msg_level, 'nick_changed', $oldnick, $newnick, $address); $msg_level = MSGLEVEL_QUITS + MSGLEVEL_NO_ACT; } } Irssi::signal_stop(); } sub query_nick_changed { my ($query, $orignick) = @_; my $msg_level = MSGLEVEL_NICKS + check_timeout( Irssi::server_find_tag($query->{server_tag}), $query->{nick}); my $active_window = Irssi::active_win(); my $active_item = $active_window->{active}; if($active_item && $active_item->{type} eq "CHANNEL" && $active_item->{server_tag} == $query->{server_tag} && $active_item->nick_find($query->{name})) { $msg_level = MSGLEVEL_NICKS + MSGLEVEL_NO_ACT; } $query->printformat($msg_level, 'nick_changed', $orignick, $query->{name}, $query->{address}); Irssi::signal_emit("window item changed", $query->window, $query); Irssi::signal_stop(); } sub check_timeout { my ($server, $nick) = @_; my $ret = 0; my $realnick = alt_deref($nick, $server->{chatnet}); if(time - $last_act_tables{$server->{tag}}{$realnick} < $min_time) { $ret = MSGLEVEL_NO_ACT; } $last_act_tables{$server->{tag}}{$realnick} = time; return $ret; } sub alt_deref { return $alt_tables{$1}{$0} || $0; } sub command_multiact { Irssi::command_runsub("multiact", @_[0], @_[1], @_[2]); } sub command_altadd { my ($data, $server, $witem) = @_; my ($chatnet, $altnick, $realnick) = split ' ', $data; if(not ($chatnet && $altnick && $realnick)) { Irssi::print('There should be thre arguments: the chatnet, the nick of the alt, and the main nick'); } if(not $alt_tables{$chatnet}) { $alt_tables{$chatnet} = {}; } $alt_tables{$chatnet}{$altnick} = $realnick; Irssi::print('Added '.$altnick.' as an alt of '.$realnick.' on '.$chatnet); } sub command_altrm { my ($data, $server, $witem) = @_; my ($chatnet, $altnick) = split ' ', $data; if(not $alt_tables{$chatnet}) { Irssi::print('there is no alt table for '.$chatnet); return; } if(not $alt_tables{$chatnet}{$altnick}) { Irssi::print('there is no realnick entry for '.$altnick.' in '.$chatnet); return; } delete($alt_tables{$chatnet}{$altnick}); Irssi::print('removed '.$altnick.' from the list of alts'); } sub command_altprint { foreach my $chatnet (keys %alt_tables) { Irssi::print($chatnet); foreach my $alt (keys %{%alt_tables->{$chatnet}}) { Irssi::print($alt.' '.$alt_tables{$chatnet}{$alt}); } } } sub command_altwrite { foreach my $chatnet (keys %alt_tables) { write_alts($chatnet); } Irssi::print('wrote alt lists for all open chatnets'); } sub command_help { Irssi::print ''; Irssi::print('ALTWRITE'); Irssi::print('writes the current alt lists to disk in ~/.irssi'); Irssi::print ''; Irssi::print('ALTPRINT'); Irssi::print ''; Irssi::print('displays the current alt lists by server, with format '. ''); Irssi::print ''; Irssi::print('ALTADD '); Irssi::print('adds altnick as an alt of realnick on server. replaces any'. 'previous realnick associated with altnick on that server.'); Irssi::print ''; Irssi::print('ALTRM '); Irssi::print("removes altnick from the list of alts on server"); Irssi::print ''; } foreach my $server (Irssi::servers()) { sig_connected($server); } Irssi::signal_add_last( { 'server connected' => \&sig_connected, 'server disconnected' => \&sig_disconnected, 'message join' => \&msg_join, 'message part' => \&msg_part, 'message quit' => \&msg_quit, 'message nick' => \&msg_nick, 'query nick changed' => \&query_nick_changed}); Irssi::command_bind('multiact', \&command_multiact); Irssi::command_bind('multiact altadd', \&command_altadd); Irssi::command_bind('multiact altprint', \&command_altprint); Irssi::command_bind('multiact altrm', \&command_altrm); Irssi::command_bind('multiact altwrite', \&command_altwrite); Irssi::command_bind("multiact help", \&command_help); Irssi::theme_register( [ 'join', '{channick_hilight $0} {chanhost_hilight $1} has joined '. '{channel $2}', 'part', '{channick $0} {chanhost $1} has left {channel $2} {reason $3}', 'quit', '{channick $0} {chanhost $1} has quit {reason $2}', 'nick_changed', '{channick $0} is now known as {channick_hilight $1}']);