aboutsummaryrefslogtreecommitdiffstats
path: root/fixery/nicklist.pl
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--fixery/nicklist.pl749
1 files changed, 749 insertions, 0 deletions
diff --git a/fixery/nicklist.pl b/fixery/nicklist.pl
new file mode 100644
index 0000000..38a2aae
--- /dev/null
+++ b/fixery/nicklist.pl
@@ -0,0 +1,749 @@
+# for documentation: see http://wouter.coekaerts.be/site/irssi/nicklist
+
+use Irssi;
+use strict;
+use IO::Handle; # for (auto)flush
+use Fcntl; # for sysopen
+
+use Data::Dumper;
+
+our $VERSION = '0.5.0';
+our %IRSSI = (
+ authors => 'Wouter Coekaerts, shabble',
+ contact => 'coekie@irssi.org, shabble+irssi@metavore.org',
+ name => 'nicklist',
+ 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, '
+ . 'https://github.com/shabble/irssi-scripts'
+ . '/blob/master/fixery/nicklist.pl',
+ changed => '10/10/2011'
+ );
+
+sub cmd_help {
+ print ( <<EOF
+Commands:
+NICKLIST HELP
+NICKLIST SCROLL <number of lines>
+NICKLIST SCREEN
+NICKLIST FIFO
+NICKLIST OFF
+NICKLIST UPDATE
+
+For help see: http://wouter.coekaerts.be/site/irssi/nicklist
+
+in short:
+
+1. FIFO MODE
+- in irssi: /NICKLIST FIFO (only the first time, to create the fifo)
+- in a shell, in a window where you want the nicklist: cat ~/.irssi/nicklistfifo
+- back in irssi:
+ /SET nicklist_heigth <height of nicklist>
+ /SET nicklist_width <width of nicklist>
+ /NICKLIST FIFO
+
+2. SCREEN MODE
+- start irssi inside screen ("screen irssi")
+- /NICKLIST SCREEN
+EOF
+ );
+}
+sub MODE_OFF () { 0 }
+sub MODE_SCREEN () { 1 }
+sub MODE_FIFO () { 2 }
+
+my $prev_lines = 0; # number of lines in previous written nicklist
+my $scroll_pos = 0; # scrolling position
+my $cursor_line; # line the cursor is currently on
+my ($OFF, $SCREEN, $FIFO) = (0,1,2); # modes
+my $mode = MODE_OFF; # current mode
+my $need_redraw = 0; # nicklist needs redrawing
+my $screen_resizing = 0; # terminal is being resized
+my $active_channel; # (REC)
+
+
+# TODO: have this use isupport('PREFIX') where supported to check mappings.
+my $server_prefix_mapping
+ = {
+ '~' => { priority => 1, sigil => '~', mode => 'q', name => 'owner' },
+ '&' => { priority => 2, sigil => '&', mode => 'a', name => 'admin' },
+ '@' => { priority => 3, sigil => '@', mode => 'o', name => 'op' },
+ '%' => { priority => 4, sigil => '%', mode => 'h', name => 'halfop' },
+ '+' => { priority => 5, sigil => '+', mode => 'v', name => 'voice' },
+ '' => { priority => 6, sigil => '', mode => '', name => 'normal' },
+ };
+
+
+# order the sigils by priority (lowest = first) from the table above.
+my @sigil_priorities = map { $_->{sigil} }
+ sort { $a->{priority} <=> $b->{priority} }
+ values %$server_prefix_mapping;
+
+
+my $sigil_cache = {};
+
+my $DEBUG = 0;
+
+sub _debug {
+ my ($msg) = @_;
+ Irssi::print($msg) if $DEBUG;
+}
+
+
+sub _select_prefix_umode {
+ my ($nick) = @_;
+ my $prefixes = { map { $_ => 1 } split '', $nick->{prefixes} };
+
+ # first check for each of the prefix sigils in given order of precedence.
+ for my $sigil_priority (@sigil_priorities) {
+ if (exists $prefixes->{$sigil_priority}) {
+ return $server_prefix_mapping->{$sigil_priority};
+ }
+ }
+ # check other properties
+ if ($nick->{op}) {
+ return $server_prefix_mapping->{'@'};
+ } elsif ($nick->{halfop}) {
+ return $server_prefix_mapping->{'%'};
+ } elsif ($nick->{voice}) {
+ return $server_prefix_mapping->{'+'};
+ } else {
+ return $server_prefix_mapping->{''};
+ }
+
+}
+
+# array of hashes, containing the internal nicklist of the active channel
+my @nicklist = ();
+# nick => realnick
+# mode =>
+# status =>
+my ($STATUS_NORMAL, $STATUS_JOINING, $STATUS_PARTING,
+ $STATUS_QUITING, $STATUS_KICKED, $STATUS_SPLIT) = (0,1,2,3,4,5);
+# text => text to be printed
+# cmp => text used to compare (sort) nicks
+
+
+# 'cached' settings
+my ($screen_prefix, $irssi_width, $height, $nicklist_width);
+
+sub read_settings {
+
+ $DEBUG = Irssi::settings_get_bool('nicklist_debug');
+
+ $screen_prefix = Irssi::settings_get_str('nicklist_screen_prefix');
+ $screen_prefix =~ s/\\e/\033/g;
+
+
+ foreach my $umode_prefix (values %$server_prefix_mapping) {
+ my $umode_name = $umode_prefix->{name};
+ my $setting_name = 'nicklist_prefix_mode_' . $umode_name;
+ my $value = Irssi::settings_get_str($setting_name);
+
+ $value = '' unless defined $value;
+ $value =~ s/\\e/\x1b/g;
+
+ $sigil_cache->{$umode_name} = $value;
+ }
+
+ if ($mode != MODE_SCREEN) {
+ $height = Irssi::settings_get_int('nicklist_height');
+ }
+ my $new_nicklist_width = Irssi::settings_get_int('nicklist_width');
+ if ($new_nicklist_width != $nicklist_width && $mode == MODE_SCREEN) {
+ sig_terminal_resized();
+ }
+ $nicklist_width = $new_nicklist_width;
+}
+
+sub update {
+ read_settings();
+ make_nicklist();
+}
+
+##################
+##### OUTPUT #####
+##################
+
+### off ###
+
+sub cmd_off {
+ if ($mode == MODE_SCREEN) {
+ screen_stop();
+ } elsif ($mode == MODE_FIFO) {
+ fifo_stop();
+ }
+}
+
+### fifo ###
+
+sub cmd_fifo_start {
+ read_settings();
+ my $path = Irssi::settings_get_str('nicklist_fifo_path');
+ unless (-p $path) { # not a pipe
+ if (-e _) { # but a something else
+ die "$0: $path exists and is not a pipe, please remove it\n";
+ } else {
+ require POSIX;
+ POSIX::mkfifo($path, 0666) or die "can\'t mkfifo $path: $!";
+ Irssi::print("Fifo created. Start reading it (\"cat $path\") and try again.");
+ return;
+ }
+ }
+ if (!sysopen(FIFO, $path, O_WRONLY | O_NONBLOCK)) { # or die "can't write $path: $!";
+ Irssi::print("Couldn\'t write to the fifo ($!). Please start reading the fifo (\"cat $path\") and try again.");
+ return;
+ }
+ FIFO->autoflush(1);
+ print FIFO "\033[2J\033[1;1H"; # erase screen & jump to 0,0
+ $cursor_line = 0;
+ if ($mode == MODE_SCREEN) {
+ screen_stop();
+ }
+ $mode = MODE_FIFO;
+ make_nicklist();
+}
+
+sub fifo_stop {
+ close FIFO;
+ $mode = MODE_OFF;
+ Irssi::print("Fifo closed.");
+}
+
+### screen ###
+
+sub cmd_screen_start {
+ if (!defined($ENV{STY})) {
+ Irssi::print 'screen not detected, screen mode only works inside screen';
+ return;
+ }
+ read_settings();
+ if ($mode == MODE_SCREEN) {
+ return;
+ }
+ if ($mode == MODE_FIFO) {
+ fifo_stop();
+ }
+ $mode = MODE_SCREEN;
+ Irssi::signal_add_last('gui print text finished', 'sig_gui_print_text_finished');
+ Irssi::signal_add_last('gui page scrolled', 'sig_page_scrolled');
+ Irssi::signal_add('terminal resized', 'sig_terminal_resized');
+ screen_size();
+ make_nicklist();
+}
+
+sub screen_stop {
+ $mode = MODE_OFF;
+ Irssi::signal_remove('gui print text finished', 'sig_gui_print_text_finished');
+ Irssi::signal_remove('gui page scrolled', 'sig_page_scrolled');
+ Irssi::signal_remove('terminal resized', 'sig_terminal_resized');
+ system 'screen -x '.$ENV{STY}.' -X fit';
+}
+
+sub screen_size {
+ if ($mode != MODE_SCREEN) {
+ return;
+ }
+ $screen_resizing = 1;
+ # fit screen
+ system 'screen -x '.$ENV{STY}.' -X fit';
+ # get size (from perldoc -q size)
+ my ($winsize, $row, $col, $xpixel, $ypixel);
+ eval 'use Term::ReadKey; ($col, $row, $xpixel, $ypixel) = GetTerminalSize';
+ # require Term::ReadKey 'GetTerminalSize';
+ # ($col, $row, $xpixel, $ypixel) = Term::ReadKey::GetTerminalSize;
+ #};
+ if ($@) { # no Term::ReadKey, try the ugly way
+ eval {
+ require 'sys/ioctl.ph';
+ # 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";
+ }
+ open my $tty, "+</dev/tty" or die "No tty: $!";
+ unless (ioctl($tty, &TIOCGWINSZ, $winsize='')) {
+ die "Term::ReadKey not found, and ioctl 'workaround' failed ($!)."
+ . " Install the Term::ReadKey perl module to use screen mode.\n";
+ }
+ 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);
+}
+
+sub sig_terminal_resized {
+ if ($screen_resizing) {
+ return;
+ }
+ $screen_resizing = 1;
+ Irssi::timeout_add_once(1000, \&screen_size, []);
+}
+
+
+### both ###
+
+sub nicklist_write_start {
+ if ($mode == MODE_SCREEN) {
+ print STDERR "\033P\033[s\033\\"; # save cursor
+ }
+}
+
+sub nicklist_write_end {
+ if ($mode == MODE_SCREEN) {
+ print STDERR "\033P\033[u\033\\"; # restore cursor
+ }
+}
+
+sub nicklist_write_line {
+ my ($line, $data) = @_;
+
+ if ($mode == MODE_SCREEN) {
+ print STDERR "\033P\033[" . ($line+1) . ';'. ($irssi_width+1) .'H'. $screen_prefix . $data . "\033\\";
+ } elsif ($mode == MODE_FIFO) {
+ $data = "\033[m$data"; # reset color
+ if ($line == $cursor_line+1) {
+ $data = "\n$data"; # next line
+ } elsif ($line == $cursor_line) {
+ $data = "\033[1G".$data; # back to beginning of line
+ } else {
+ $data = "\033[".($line+1).";0H".$data; # jump
+ }
+ $cursor_line=$line;
+ print(FIFO $data) or fifo_stop();
+ }
+}
+
+# recalc the text of the nicklist item
+sub calc_text {
+ my ($nick) = @_;
+
+ # handle truncation of long nicks.
+ my $tmp = $nicklist_width - 3;
+
+ my $text = $nick->{nick};
+ $text =~ s/^(.{$tmp})..+$/$1\033[34m~\033[m/;
+
+ my $mode = $nick->{mode};
+
+ $nick->{text} = $sigil_cache->{$mode->{name}} . $text .
+ (' ' x ($nicklist_width - length($nick->{nick}) - 1));
+
+ $nick->{cmp} = $mode->{priority} . lc($nick->{nick});
+}
+
+# redraw the given nick (nr) if it is visible
+sub redraw_nick_nr {
+ my ($nr) = @_;
+ my $line = $nr - $scroll_pos;
+ if ($line >= 0 && $line < $height) {
+ nicklist_write_line($line, $nicklist[$nr]->{text});
+ }
+}
+
+# nick was inserted, redraw area if necessary
+sub draw_insert_nick_nr {
+ my ($nr) = @_;
+ my $line = $nr - $scroll_pos;
+ if ($line < 0) { # nick is inserted above visible area
+ $scroll_pos++; # 'scroll' down :)
+ } elsif ($line < $height) { # line is visible
+ if ($mode == MODE_SCREEN) {
+ need_redraw();
+ } elsif ($mode == MODE_FIFO) {
+ # reset color & insert line & write nick
+ my $data = "\033[m\033[L". $nicklist[$nr]->{text};
+ if ($line == $cursor_line) {
+ $data = "\033[1G".$data; # back to beginning of line
+ } else {
+ $data = "\033[".($line+1).";1H".$data; # jump
+ }
+ $cursor_line=$line;
+ print(FIFO $data) or fifo_stop();
+ if ($prev_lines < $height) {
+ $prev_lines++; # the nicklist has one line more
+ }
+ }
+ }
+}
+
+sub draw_remove_nick_nr {
+ my ($nr) = @_;
+ my $line = $nr - $scroll_pos;
+ if ($line < 0) { # nick removed above visible area
+ $scroll_pos--; # 'scroll' up :)
+ } elsif ($line < $height) { # line is visible
+ if ($mode == MODE_SCREEN) {
+ need_redraw();
+ } elsif ($mode == MODE_FIFO) {
+ #my $data = "\033[m\033[L[i$line]". $nicklist[$nr]->{text}; # reset color & insert line & write nick
+ my $data = "\033[M"; # delete line
+ if ($line != $cursor_line) {
+ $data = "\033[".($line+1)."d".$data; # jump
+ }
+ $cursor_line=$line;
+ print(FIFO $data) or fifo_stop();
+ if (@nicklist-$scroll_pos >= $height) {
+ redraw_nick_nr($scroll_pos+$height-1);
+ }
+ }
+ }
+}
+
+# redraw the whole nicklist
+sub redraw {
+ $need_redraw = 0;
+ #make_nicklist();
+ nicklist_write_start();
+ my $line = 0;
+ ### draw nicklist ###
+ for (my $i=$scroll_pos;$line < $height && $i < @nicklist; $i++) {
+ nicklist_write_line($line++, $nicklist[$i]->{text});
+ }
+
+ ### clean up other lines ###
+ my $real_lines = $line;
+ while ($line < $prev_lines) {
+ nicklist_write_line($line++,' ' x $nicklist_width);
+ }
+ $prev_lines = $real_lines;
+ nicklist_write_end();
+}
+
+# redraw (with little delay to avoid redrawing to much)
+sub need_redraw {
+ if (!$need_redraw) {
+ $need_redraw = 1;
+ Irssi::timeout_add_once(10, \&redraw, []);
+ }
+}
+
+sub sig_page_scrolled {
+ $prev_lines = $height; # we'll need to redraw everything if he scrolled up
+ need_redraw;
+}
+
+# redraw (with delay) if the window is visible (only in screen mode)
+sub sig_gui_print_text_finished {
+ if ($need_redraw) { # there's already a redraw 'queued'
+ return;
+ }
+ my $window = @_[0];
+ if ($window->{refnum} == Irssi::active_win->{refnum} || Irssi::settings_get_str('nicklist_screen_split_windows') eq '*') {
+ need_redraw;
+ return;
+ }
+ foreach my $win (split(/[ ,]/, Irssi::settings_get_str('nicklist_screen_split_windows'))) {
+ if ($window->{refnum} == $win || $window->{name} eq $win) {
+ need_redraw;
+ return;
+ }
+ }
+}
+
+####################
+##### NICKLIST #####
+####################
+
+# returns the position of the given nick(as string) in the (internal) nicklist
+sub find_nick {
+ my ($nick) = @_;
+ for (my $i=0;$i < @nicklist; $i++) {
+ if ($nicklist[$i]->{nick} eq $nick) {
+ return $i;
+ }
+ }
+ return -1;
+}
+
+# find position where nick should be inserted into the list
+sub find_insert_pos {
+ my ($cmp)= @_;
+ for (my $i=0;$i < @nicklist; $i++) {
+ if ($nicklist[$i]->{cmp} gt $cmp) {
+ return $i;
+ }
+ }
+ return scalar(@nicklist); #last
+}
+
+# make the (internal) nicklist (@nicklist)
+sub make_nicklist {
+ @nicklist = ();
+ $scroll_pos = 0;
+
+ ### get & check channel ###
+ my $channel = Irssi::active_win->{active};
+
+ if (!$channel || (ref($channel) ne 'Irssi::Irc::Channel' && ref($channel) ne
+ 'Irssi::Silc::Channel') || $channel->{type} ne 'CHANNEL' ||
+ ($channel->{chat_type} ne 'SILC' && !$channel->{names_got}) ) {
+
+ $active_channel = undef;
+ # no nicklist
+ } else {
+ $active_channel = $channel;
+
+ ### make nicklist ###
+ my @nicks = $channel->nicks();
+
+ my @mode_decorated_nicks =
+ map { [ _select_prefix_umode($_), $_ ] } @nicks;
+
+ my @sorted_nicks = map { $_->[1] }
+ sort sort_prefixed_nicks @mode_decorated_nicks;
+
+ # TODO: find a way to reuse these prefix lookups.
+ #_debug(Dumper(\@sorted_nicks));
+
+ foreach my $nick (@sorted_nicks) {
+
+ my $this_nick = {
+ nick => $nick->{nick},
+ mode => _select_prefix_umode($nick),
+ };
+
+ calc_text($this_nick);
+ push @nicklist, $this_nick;
+ }
+ }
+ need_redraw();
+}
+
+sub sort_prefixed_nicks {
+ ($a->[0]->{priority} . lc $a->[1]->{nick})
+ cmp
+ ($b->[0]->{priority} . lc $b->[1]->{nick});
+}
+
+# insert nick(as hash) into nicklist
+# pre: cmp has to be calculated
+sub insert_nick {
+ my ($nick) = @_;
+ my $nr = find_insert_pos($nick->{cmp});
+ splice @nicklist, $nr, 0, $nick;
+ draw_insert_nick_nr($nr);
+}
+
+# remove nick(as nr) from nicklist
+sub remove_nick {
+ my ($nr) = @_;
+ splice @nicklist, $nr, 1;
+ draw_remove_nick_nr($nr);
+}
+
+###################
+##### ACTIONS #####
+###################
+
+# scroll the nicklist, arg = number of lines to scroll, positive = down, negative = up
+sub cmd_scroll {
+ if (!$active_channel) { # not a channel active
+ return;
+ }
+ my @nicks=Irssi::active_win->{active}->nicks;
+ my $nick_count = scalar(@nicks)+0;
+ my $channel = Irssi::active_win->{active};
+ if (!$channel || $channel->{type} ne 'CHANNEL' || !$channel->{names_got} || $nick_count <= Irssi::settings_get_int('nicklist_height')) {
+ return;
+ }
+ $scroll_pos += @_[0];
+
+ if ($scroll_pos > $nick_count - $height) {
+ $scroll_pos = $nick_count - $height;
+ }
+ if ($scroll_pos <= 0) {
+ $scroll_pos = 0;
+ }
+ need_redraw();
+}
+
+sub is_active_channel {
+ my ($server,$channel) = @_; # (channel as string)
+ return ($server && $server->{tag} eq $active_channel->{server}->{tag} && $server->channel_find($channel) && $active_channel && $server->channel_find($channel)->{name} eq $active_channel->{name});
+}
+
+sub sig_channel_wholist { # this is actualy a little late, when the names are received would be better
+ my ($channel) = @_;
+ if (Irssi::active_win->{active} && Irssi::active_win->{active}->{name} eq $channel->{name}) { # the channel joined is active
+ make_nicklist
+ }
+}
+
+sub sig_join {
+ my ($server,$channel,$nick,$address) = @_;
+ if (!is_active_channel($server,$channel)) {
+ return;
+ }
+ my $newnick = {
+ nick => $nick,
+ mode => $server_prefix_mapping->{''}
+ };
+ calc_text($newnick);
+ insert_nick($newnick);
+}
+
+sub sig_kick {
+ my ($server, $channel, $nick, $kicker, $address, $reason) = @_;
+ if (!is_active_channel($server,$channel)) {
+ return;
+ }
+ my $nr = find_nick($nick);
+ if ($nr == -1) {
+ Irssi::print("nicklist warning: $nick was kicked from $channel, but not found in nicklist");
+ } else {
+ remove_nick($nr);
+ }
+}
+
+sub sig_part {
+ my ($server,$channel,$nick,$address, $reason) = @_;
+ if (!is_active_channel($server,$channel)) {
+ return;
+ }
+ my $nr = find_nick($nick);
+ if ($nr == -1) {
+ Irssi::print("nicklist warning: $nick has parted $channel, but was not found in nicklist");
+ } else {
+ remove_nick($nr);
+ }
+
+}
+
+sub sig_quit {
+ my ($server,$nick,$address, $reason) = @_;
+ if ($server->{tag} ne $active_channel->{server}->{tag}) {
+ return;
+ }
+ my $nr = find_nick($nick);
+ if ($nr != -1) {
+ remove_nick($nr);
+ }
+}
+
+sub sig_nick {
+ my ($server, $newnick, $oldnick, $address) = @_;
+ if ($server->{tag} ne $active_channel->{server}->{tag}) {
+ return;
+ }
+ my $nr = find_nick($oldnick);
+ if ($nr != -1) { # if nick was found (nickchange is in current channel)
+ my $nick = $nicklist[$nr];
+ remove_nick($nr);
+
+ $nick->{nick} = $newnick;
+
+ calc_text($nick);
+ insert_nick($nick);
+ }
+}
+
+sub sig_mode {
+ my ($channel, $nick, $setby, $mode, $type) = @_; # (nick and channel as rec)
+ if ($channel->{server}->{tag} ne $active_channel->{server}->{tag} || $channel->{name} ne $active_channel->{name}) {
+ return;
+ }
+ my $nr = find_nick($nick->{nick});
+ if ($nr == -1) {
+ Irssi::print("nicklist warning: $nick->{nick} had mode set on " .
+ "$channel->{name}, but was not found in nicklist");
+ } else {
+ my $nicklist_item = $nicklist[$nr];
+ remove_nick($nr);
+
+ $nicklist_item->{mode} = _select_prefix_umode($nick);
+
+# $nicklist_item->{mode} = ($nick->{op}?$MODE_OP:$nick->{halfop}?$MODE_HALFOP:$nick->{voice}?$MODE_VOICE:$MODE_NORMAL);
+
+ calc_text($nicklist_item);
+ insert_nick($nicklist_item);
+ }
+}
+
+##### command binds #####
+Irssi::command_bind 'nicklist' => sub {
+ my ( $data, $server, $item ) = @_;
+ $data =~ s/\s+$//g;
+ Irssi::command_runsub ('nicklist', $data, $server, $item ) ;
+};
+Irssi::signal_add_first 'default command nicklist' => sub {
+ # gets triggered if called with unknown subcommand
+ cmd_help();
+};
+Irssi::command_bind('nicklist update',\&update);
+Irssi::command_bind('nicklist help',\&cmd_help);
+Irssi::command_bind('nicklist scroll',\&cmd_scroll);
+Irssi::command_bind('nicklist fifo',\&cmd_fifo_start);
+Irssi::command_bind('nicklist screen',\&cmd_screen_start);
+Irssi::command_bind('nicklist screensize',\&screen_size);
+Irssi::command_bind('nicklist off',\&cmd_off);
+
+##### signals #####
+Irssi::signal_add_last('window item changed', \&make_nicklist);
+Irssi::signal_add_last('window changed', \&make_nicklist);
+Irssi::signal_add_last('channel wholist', \&sig_channel_wholist);
+Irssi::signal_add_first('message join', \&sig_join); # first, to be before ignores
+Irssi::signal_add_first('message part', \&sig_part);
+Irssi::signal_add_first('message kick', \&sig_kick);
+Irssi::signal_add_first('message quit', \&sig_quit);
+Irssi::signal_add_first('message nick', \&sig_nick);
+Irssi::signal_add_first('message own_nick', \&sig_nick);
+Irssi::signal_add_first('nick mode changed', \&sig_mode);
+
+Irssi::signal_add('setup changed', \&read_settings);
+
+##### settings #####
+Irssi::settings_add_str('nicklist', 'nicklist_screen_prefix', '\e[m ');
+Irssi::settings_add_str('nicklist', 'nicklist_screen_mode_suffix', '\e[39m');
+
+Irssi::settings_add_str('nicklist', 'nicklist_prefix_mode_owner', '\e[31m~\e[39m');
+Irssi::settings_add_str('nicklist', 'nicklist_prefix_mode_admin', '\e[33m&\e[39m');
+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[3m+\e[39m');
+Irssi::settings_add_str('nicklist', 'nicklist_prefix_mode_normal', ' ');
+
+
+Irssi::settings_add_int('nicklist', 'nicklist_width',11);
+Irssi::settings_add_int('nicklist', 'nicklist_height',24);
+
+Irssi::settings_add_str('nicklist', 'nicklist_fifo_path',
+ Irssi::get_irssi_dir . '/nicklistfifo');
+
+Irssi::settings_add_str('nicklist', 'nicklist_screen_split_windows', '');
+Irssi::settings_add_str('nicklist', 'nicklist_automode', '');
+
+Irssi::settings_add_bool('nicklist', 'nicklist_debug', 0);
+
+read_settings();
+
+if (uc(Irssi::settings_get_str('nicklist_automode')) eq 'SCREEN') {
+ cmd_screen_start();
+} elsif (uc(Irssi::settings_get_str('nicklist_automode')) eq 'FIFO') {
+ cmd_fifo_start();
+}
+