]> git.99rst.org Git - irssi-scripts.irssi.org.git/commitdiff
[nicklist][#486] add patch 0.4.6+
authorcoekie <redacted>
Mon, 2 Apr 2018 21:32:07 +0000 (23:32 +0200)
committerbw1 <redacted>
Mon, 2 Apr 2018 21:43:10 +0000 (23:43 +0200)
scripts/nicklist.pl

index 98e62b38ffde4060e1a1f9ec8650b3b44479f264..2690e26ce63098f8107cf2c4544f306562808c6c 100755 (executable)
@@ -1,11 +1,28 @@
+# This script adds a nicklist to the right of irssi
 # for documentation: see http://wouter.coekaerts.be/site/irssi/nicklist
 
+# Copyright (C) 2002-2007  Wouter Coekaerts <coekie@irssi.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
 use Irssi;
 use strict;
 use IO::Handle; # for (auto)flush
 use Fcntl; # for sysopen
 use vars qw($VERSION %IRSSI);
-$VERSION = '0.4.9';
+$VERSION = '0.4.10';
 %IRSSI = (
        authors     => 'Wouter Coekaerts',
        contact     => 'coekie@irssi.org',
@@ -13,7 +30,7 @@ $VERSION = '0.4.9';
        description => 'draws a nicklist to another terminal, or at the right of your irssi in the same terminal',
        license     => 'GPLv2',
        url         => 'http://wouter.coekaerts.be/irssi',
-       changed     => '28/06/2017'
+       changed     => '2018-04-02'
 );
 
 sub cmd_help {
@@ -58,25 +75,47 @@ my $active_channel;                  # (REC)
 
 my @nicklist=();                     # array of hashes, containing the internal nicklist of the active channel
        # nick => realnick
-       # mode =>
-       my ($MODE_OP, $MODE_HALFOP, $MODE_VOICE, $MODE_NORMAL) = (0,1,2,3);
-       # status =>
-       my ($STATUS_NORMAL, $STATUS_JOINING, $STATUS_PARTING, $STATUS_QUITING, $STATUS_KICKED, $STATUS_SPLIT) = (0,1,2,3,4,5);
+       # modeflag => '@', '%', '+', or other mode char
+       # modepos => number representing the position in which to sort nicks with that mode
+       # status => (not used yet...)
        # text => text to be printed
        # cmp => text used to compare (sort) nicks
 
-
 # 'cached' settings
-my ($screen_prefix, $irssi_width, @prefix_mode, @prefix_status, $height, $nicklist_width);
+my ($screen_prefix, $irssi_width, %prefix_mode, @prefix_status, $height, $nicklist_width, $check_friends, @prefix_friends);
 
 sub read_settings {
        ($screen_prefix = Irssi::settings_get_str('nicklist_screen_prefix')) =~ s/\\e/\033/g;
 
-       ($prefix_mode[$MODE_OP] = Irssi::settings_get_str('nicklist_prefix_mode_op')) =~ s/\\e/\033/g;
-       ($prefix_mode[$MODE_HALFOP] = Irssi::settings_get_str('nicklist_prefix_mode_halfop')) =~ s/\\e/\033/g;
-       ($prefix_mode[$MODE_VOICE] = Irssi::settings_get_str('nicklist_prefix_mode_voice')) =~ s/\\e/\033/g;
-       ($prefix_mode[$MODE_NORMAL] = Irssi::settings_get_str('nicklist_prefix_mode_normal')) =~ s/\\e/\033/g;
-       
+       ($prefix_mode{'@'} = Irssi::settings_get_str('nicklist_prefix_mode_op')) =~ s/\\e/\033/g;
+       ($prefix_mode{'%'} = Irssi::settings_get_str('nicklist_prefix_mode_halfop')) =~ s/\\e/\033/g;
+       ($prefix_mode{'+'} = Irssi::settings_get_str('nicklist_prefix_mode_voice')) =~ s/\\e/\033/g;
+       ($prefix_mode{' '} = Irssi::settings_get_str('nicklist_prefix_mode_normal')) =~ s/\\e/\033/g;
+
+       (my $prefix_mode_other = Irssi::settings_get_str('nicklist_prefix_mode_other')) =~ s/\\e/\033/g;
+       foreach my $p (split (/ /, $prefix_mode_other)) {
+               next if $p eq '';
+               if ($p !~ /(.)=(.*)/) {
+                       Irssi::print("Could not parse nicklist_prefix_mode_other part '$p'. Expected space separated list of <mode character>=<prefix>");
+                       last;
+               } else {
+                       $prefix_mode{$1} = $2;
+               }
+       }
+
+       (my $prefix_friends = Irssi::settings_get_str('nicklist_prefix_friends')) =~ s/\\e/\033/g;
+       foreach my $p (split (/ /, $prefix_friends)) {
+               next if $p eq '';
+               if ($p !~ /(.+?)=(.*)/) {
+                       Irssi::print("Could not parse nicklist_prefix_friends part '$p'. Expected space separated list of <flags>=<prefix>");
+                       last;
+               } else {
+                       push @prefix_friends, {'flags' => $1, 'prefix' => $2};
+               }
+       }
+
+       $check_friends = ($prefix_friends ne '');
+
        if ($mode != $SCREEN) {
                $height = Irssi::settings_get_int('nicklist_height');
        }
@@ -187,8 +226,11 @@ sub screen_stop {
        Irssi::signal_remove('gui page scrolled', \&sig_page_scrolled);
        Irssi::signal_remove('terminal resized', \&sig_terminal_resized);
        system 'screen -x '.$ENV{'STY'}.' -X fit';
+       # we wait a second to make sure the fit command was processed
+       Irssi::timeout_add_once(1000, \&screen_size, []);
 }
 
+#sub screen_size_real {
 sub screen_size {
        if ($mode != $SCREEN) {
                return;
@@ -208,10 +250,10 @@ sub screen_size {
                        # without this reloading doesn't work. workaround for some unknown bug
                        do 'asm/ioctls.ph';
                };
-               
+
                # ugly way not working, let's try something uglier, the dg-hack(tm) (constant for linux only?)
                if($@) { no strict 'refs'; *TIOCGWINSZ = sub { return 0x5413 } }
-               
+
                unless (defined &TIOCGWINSZ) {
                        die "Term::ReadKey not found, and ioctl 'workaround' failed. Install the Term::ReadKey perl module to use screen mode.\n";
                }
@@ -222,19 +264,14 @@ sub screen_size {
                close(TTY);
                ($row, $col, $xpixel, $ypixel) = unpack('S4', $winsize);
        }
-       
+
        # set screen width
        $irssi_width = $col-$nicklist_width-1;
        $height = $row-1;
-       
-       # on some recent systems, "screen -X fit; screen -X width -w 50" doesn't work, needs a sleep in between the 2 commands
-       # so we wait a second before setting the width
-       Irssi::timeout_add_once(1000, sub {
-               my ($new_irssi_width) = @_;
-               system 'screen -x '.$ENV{'STY'}.' -X width -w ' . $new_irssi_width;
-               # and then we wait another second for the resizing, and then redraw.
-               Irssi::timeout_add_once(1000,sub {$screen_resizing = 0; redraw()}, []);
-       }, $irssi_width);
+
+       system 'screen -x '.$ENV{'STY'}.' -X width -w ' . $irssi_width;
+       # wait another second for the resizing, and then redraw.
+       Irssi::timeout_add_once(1000,sub {$screen_resizing = 0; redraw()}, []);
 }
 
 sub sig_terminal_resized {
@@ -278,13 +315,50 @@ sub nicklist_write_line {
        }
 }
 
+sub calc_prefix_friends {
+       my ($nick) = @_;
+
+       return '' unless $check_friends
+               && $nick->{'host'}
+               && is_friend($active_channel->{'server'}->{'chatnet'}, $active_channel->{'name'}, $nick->{'nick'}, $nick->{'host'});
+
+       my $flags = get_flags($active_channel->{'server'}->{'chatnet'}, $active_channel->{'name'}, $nick->{'nick'}, $nick->{'host'});
+
+       my $prefix;
+       foreach my $prefix_friend (@prefix_friends) {
+               if ($prefix_friend->{'flags'} eq 'noflag') {
+                       if ($flags eq '') {
+                               $prefix = $prefix_friend->{'prefix'};
+                               last;
+                       }
+               } elsif (check_modes($flags, $prefix_friend->{'flags'})) {
+                       $prefix = $prefix_friend->{'prefix'};
+               }
+       }
+
+       return $prefix ? $prefix : '';
+}
+
 # recalc the text of the nicklist item
 sub calc_text {
        my ($nick) = @_;
        my $tmp = $nicklist_width-3;
-       (my $text = $nick->{'nick'}) =~ s/^(.{$tmp})..+$/$1\033[34m~\033[m/;
-       $nick->{'text'} = $prefix_mode[$nick->{'mode'}] . $text . (' ' x ($nicklist_width-length($nick->{'nick'})-1));
-       $nick->{'cmp'} = $nick->{'mode'}.lc($nick->{'nick'});
+       (my $text = $nick->{'nick'}) =~ s/^(.{$tmp})..+$/$1\033[34m~/; # strip nick if too long
+
+       my $prefix_mode = $prefix_mode{$nick->{'modeflag'}};
+       if (! defined($prefix_mode) ) {
+               $prefix_mode = $nick->{'modeflag'};
+       }
+
+       my $prefix_friends = calc_prefix_friends($nick);
+
+       $nick->{'text'} =
+               $prefix_mode .
+               $prefix_friends .
+               $text .
+               (' ' x ($nicklist_width-length($nick->{'nick'})-1)) .
+               "\033[m"; # reset
+       $nick->{'cmp'} = $nick->{'modepos'}.lc($nick->{'nick'});
 }
 
 # redraw the given nick (nr) if it is visible
@@ -395,6 +469,95 @@ sub sig_gui_print_text_finished {
        }
 }
 
+###################
+##### FRIENDS #####
+###################
+
+# checks if $has_modes is in $need_modes, copied from trigger.pl
+sub check_modes {
+       my ($has_modes, $need_modes) = @_;
+       my $matches;
+       my $switch = 1; # if a '-' if found, will be 0 (meaning the modes should not be set)
+       foreach my $need_mode (split /&/,$need_modes) {
+               $matches = 0;
+               foreach my $char (split //,$need_mode) {
+                       if ($char eq '-') {
+                               $switch = 0;
+                       } elsif ($char eq '+') {
+                               $switch = 1;
+                       } elsif ((index($has_modes,$char) != -1) == $switch) {
+                               $matches = 1;
+                               last;
+                       }
+               }
+               if (!$matches) {
+                       return 0;
+               }
+       }
+       return 1;
+}
+
+# get someones flags from people.pl or friends(_shasta).pl, copied from trigger.pl
+sub get_flags {
+       my ($chatnet, $channel, $nick, $address) = @_;
+       my $flags;
+       no strict 'refs';
+       if (%{ 'Irssi::Script::people::' }) {
+               if (defined ($channel)) {
+                       $flags = (&{ 'Irssi::Script::people::find_local_flags' }($chatnet,$channel,$nick,$address));
+               } else {
+                       $flags = (&{ 'Irssi::Script::people::find_global_flags' }($chatnet,$nick,$address));
+               }
+               $flags = join('',keys(%{$flags}));
+       } else {
+               my $shasta;
+               if (%{ 'Irssi::Script::friends_shasta::' }) {
+                       $shasta = 'friends_shasta';
+               } elsif (defined &{ 'Irssi::Script::friends::get_idx' }) {
+                       $shasta = 'friends';
+               }
+               if (!$shasta) {
+                       return undef;
+               }
+               my $idx = (&{ 'Irssi::Script::'.$shasta.'::get_idx' }($nick,$address));
+               if ($idx == -1) {
+                       return '';
+               }
+               $flags = (&{ 'Irssi::Script::'.$shasta.'::get_friends_flags' }($idx,undef));
+               if ($channel) {
+                       $flags .= (&{ 'Irssi::Script::'.$shasta.'::get_friends_flags' }($idx,$channel));
+               }
+       }
+       return $flags;
+}
+
+sub is_friend {
+       my ($chatnet, $channel, $nick, $address) = @_;
+       no strict 'refs';
+       if (%{ 'Irssi::Script::people::' }) {
+               return (() != &{'Irssi::Script::people::find_users'}($chatnet, $nick, $address));
+               my $flags;
+               if (defined ($channel)) {
+                       $flags = (&{ 'Irssi::Script::people::find_local_flags' }($chatnet,$channel,$nick,$address));
+               } else {
+                       $flags = (&{ 'Irssi::Script::people::find_global_flags' }($chatnet,$nick,$address));
+               }
+               return ($flags ne ''); # TODO: test this
+       } else {
+               my $shasta;
+               if (%{ 'Irssi::Script::friends_shasta::' }) {
+                       $shasta = 'friends_shasta';
+               } elsif (defined &{ 'Irssi::Script::friends::get_idx' }) {
+                       $shasta = 'friends';
+               }
+               if (!$shasta) {
+                       return undef;
+               }
+               my $idx = (&{ 'Irssi::Script::'.$shasta.'::get_idx' }($nick,$address));
+               return ($idx != -1);
+       }
+}
+
 ####################
 ##### NICKLIST #####
 ####################
@@ -435,13 +598,12 @@ sub make_nicklist {
        } else {
                $active_channel = $channel;
                ### make nicklist ###
-               my $thisnick;
-               foreach my $nick (sort {(($a->{'op'}?'1':$a->{'halfop'}?'2':$a->{'voice'}?'3':'4').lc($a->{'nick'}))
-                                   cmp (($b->{'op'}?'1':$b->{'halfop'}?'2':$b->{'voice'}?'3':'4').lc($b->{'nick'}))} $channel->nicks()) {
-                       $thisnick = {'nick' => $nick->{'nick'}, 'mode' => ($nick->{'op'}?$MODE_OP:$nick->{'halfop'}?$MODE_HALFOP:$nick->{'voice'}?$MODE_VOICE:$MODE_NORMAL)};
-                       calc_text($thisnick);
+               foreach my $nick ($channel->nicks()) {
+                       my $thisnick = {'nick' => $nick->{'nick'}};
+                       recalc_nick($thisnick, $nick);
                        push @nicklist, $thisnick;
                }
+               @nicklist = sort {$a->{'cmp'} cmp $b->{'cmp'}} @nicklist;
        }
        need_redraw();
 }
@@ -462,21 +624,49 @@ sub remove_nick {
        draw_remove_nick_nr($nr);
 }
 
+# update the mode and cmp of a nick, based on a nickrec from irssi
+sub recalc_nick {
+       my ($nick, $nickrec) = @_;
+       if (! $nickrec) {
+               $nickrec = $active_channel->nick_find($nick->{'nick'});
+       }
+
+       my $nickflags = $active_channel->{'server'}->get_nick_flags() . ' ';
+
+       my $flag = (
+               $nickrec->{'op'} ? '@' :
+               $nickrec->{'halfop'} ? '%' :
+               $nickrec->{'voice'} ? '+' :
+               ' '
+       );
+
+       if ($nickrec->{'other'} && index($nickflags, $nick->{'other'}) < index($nickflags, $flag)) {
+               $flag = chr($nickrec->{'other'});
+       }
+
+       $nick->{'modepos'} = index($nickflags, $flag);
+       $nick->{'modeflag'} = $flag;
+
+       $nick->{'host'} = $nickrec->{'host'};
+       calc_text($nick);
+}
+
 ###################
 ##### ACTIONS #####
 ###################
 
 # scroll the nicklist, arg = number of lines to scroll, positive = down, negative = up
 sub cmd_scroll {
+       my $channel = Irssi::active_win->{active};
+       my @nicks = $channel->nicks;
+       my $nick_count = scalar(@nicks)+0;
+
        if (!$active_channel) { # not a channel active
                return;
        }
-       my $channel = Irssi::active_win->{active};
-       if (!$channel || $channel->{type} ne 'CHANNEL' || !$channel->{names_got}) {
+       if (!$channel || $channel->{type} ne 'CHANNEL' || !$channel->{names_got} || $nick_count <= $height) {
                return;
        }
-       my @nicks = $channel->nicks;
-       my $nick_count = scalar(@nicks)+0;
        if ($nick_count <= Irssi::settings_get_int('nicklist_height')) {
                return;
        }
@@ -508,8 +698,8 @@ sub sig_join {
        if (!is_active_channel($server,$channel)) {
                return;
        }
-       my $newnick = {'nick' => $nick, 'mode' => $MODE_NORMAL};
-       calc_text($newnick);
+       my $newnick = {'nick' => $nick};
+       recalc_nick($newnick);
        insert_nick($newnick);
 }
 
@@ -577,8 +767,7 @@ sub sig_mode {
        } else {
                my $nicklist_item = $nicklist[$nr];
                remove_nick($nr);
-               $nicklist_item->{'mode'} = ($nick->{'op'}?$MODE_OP:$nick->{'halfop'}?$MODE_HALFOP:$nick->{'voice'}?$MODE_VOICE:$MODE_NORMAL);
-               calc_text($nicklist_item);
+               recalc_nick($nicklist_item, $nick);
                insert_nick($nicklist_item);
        }
 }
@@ -623,6 +812,8 @@ Irssi::settings_add_str('nicklist', 'nicklist_prefix_mode_op', '\e[32m@\e[39m');
 Irssi::settings_add_str('nicklist', 'nicklist_prefix_mode_halfop', '\e[34m%\e[39m');
 Irssi::settings_add_str('nicklist', 'nicklist_prefix_mode_voice', '\e[33m+\e[39m');
 Irssi::settings_add_str('nicklist', 'nicklist_prefix_mode_normal', ' ');
+Irssi::settings_add_str('nicklist', 'nicklist_prefix_mode_other', '&=\e[31m&\e[39m ~=\e[35m~\e[39m');
+Irssi::settings_add_str('nicklist', 'nicklist_prefix_friends', 'o=\e[32m v=\e[33m noflag=\e[1m');
 
 Irssi::settings_add_int('nicklist', 'nicklist_width',11);
 Irssi::settings_add_int('nicklist', 'nicklist_height',24);
git clone https://git.99rst.org/PROJECT