html/nicklist.pl


   1 # for documentation: see http://wouter.coekaerts.be/site/irssi/nicklist
   2 
   3 use Irssi;
   4 use strict;
   5 use IO::Handle; # for (auto)flush
   6 use Fcntl; # for sysopen
   7 use vars qw($VERSION %IRSSI);
   8 $VERSION = '0.4.6';
   9 %IRSSI = (
  10 	authors     => 'Wouter Coekaerts',
  11 	contact     => 'coekie@irssi.org',
  12 	name        => 'nicklist',
  13 	description => 'draws a nicklist to another terminal, or at the right of your irssi in the same terminal',
  14 	license     => 'GPLv2',
  15 	url         => 'http://wouter.coekaerts.be/irssi',
  16 	changed     => '29/06/2004'
  17 );
  18 
  19 sub cmd_help {
  20 	print ( <<EOF
  21 Commands:
  22 NICKLIST HELP
  23 NICKLIST SCROLL <nr of lines>
  24 NICKLIST SCREEN
  25 NICKLIST FIFO
  26 NICKLIST OFF
  27 NICKLIST UPDATE
  28 
  29 For help see: http://wouter.coekaerts.be/site/irssi/nicklist
  30 
  31 in short:
  32 
  33 1. FIFO MODE
  34 - in irssi: /NICKLIST FIFO (only the first time, to create the fifo)
  35 - in a shell, in a window where you want the nicklist: cat ~/.irssi/nicklistfifo
  36 - back in irssi:
  37     /SET nicklist_heigth <height of nicklist>
  38     /SET nicklist_width <width of nicklist>
  39     /NICKLIST FIFO
  40 
  41 2. SCREEN MODE
  42 - start irssi inside screen ("screen irssi")
  43 - /NICKLIST SCREEN
  44 EOF
  45     );
  46 }
  47 
  48 my $prev_lines = 0;                  # number of lines in previous written nicklist
  49 my $scroll_pos = 0;                  # scrolling position
  50 my $cursor_line;                     # line the cursor is currently on
  51 my ($OFF, $SCREEN, $FIFO) = (0,1,2); # modes
  52 my $mode = $OFF;                     # current mode
  53 my $need_redraw = 0;                 # nicklist needs redrawing
  54 my $screen_resizing = 0;             # terminal is being resized
  55 my $active_channel;                  # (REC)
  56 
  57 my @nicklist=();                     # array of hashes, containing the internal nicklist of the active channel
  58 	# nick => realnick
  59 	# mode =>
  60 	my ($MODE_OP, $MODE_HALFOP, $MODE_VOICE, $MODE_NORMAL) = (0,1,2,3);
  61 	# status =>
  62 	my ($STATUS_NORMAL, $STATUS_JOINING, $STATUS_PARTING, $STATUS_QUITING, $STATUS_KICKED, $STATUS_SPLIT) = (0,1,2,3,4,5);
  63 	# text => text to be printed
  64 	# cmp => text used to compare (sort) nicks
  65 
  66 
  67 # 'cached' settings
  68 my ($screen_prefix, $irssi_width, @prefix_mode, @prefix_status, $height, $nicklist_width);
  69 
  70 sub read_settings {
  71 	($screen_prefix = Irssi::settings_get_str('nicklist_screen_prefix')) =~ s/\\e/\033/g;
  72 
  73 	($prefix_mode[$MODE_OP] = Irssi::settings_get_str('nicklist_prefix_mode_op')) =~ s/\\e/\033/g;
  74 	($prefix_mode[$MODE_HALFOP] = Irssi::settings_get_str('nicklist_prefix_mode_halfop')) =~ s/\\e/\033/g;
  75 	($prefix_mode[$MODE_VOICE] = Irssi::settings_get_str('nicklist_prefix_mode_voice')) =~ s/\\e/\033/g;
  76 	($prefix_mode[$MODE_NORMAL] = Irssi::settings_get_str('nicklist_prefix_mode_normal')) =~ s/\\e/\033/g;
  77 	
  78 	if ($mode != $SCREEN) {
  79 		$height = Irssi::settings_get_int('nicklist_height');
  80 	}
  81 	my $new_nicklist_width = Irssi::settings_get_int('nicklist_width');
  82 	if ($new_nicklist_width != $nicklist_width && $mode == $SCREEN) {
  83 		sig_terminal_resized();
  84 	}
  85 	$nicklist_width = $new_nicklist_width;
  86 }
  87 
  88 sub update {
  89 	read_settings();
  90 	make_nicklist();
  91 }
  92 
  93 ##################
  94 ##### OUTPUT #####
  95 ##################
  96 
  97 ### off ###
  98 
  99 sub cmd_off {
 100 	if ($mode == $SCREEN) {
 101 		screen_stop();
 102 	} elsif ($mode == $FIFO) {
 103 		fifo_stop();
 104 	}
 105 }
 106 
 107 ### fifo ###
 108 
 109 sub cmd_fifo_start {
 110 	read_settings();
 111 	my $path = Irssi::settings_get_str('nicklist_fifo_path');
 112 	unless (-p $path) { # not a pipe
 113 	    if (-e _) { # but a something else
 114 	        die "$0: $path exists and is not a pipe, please remove it\n";
 115 	    } else {
 116 	        require POSIX;
 117 	        POSIX::mkfifo($path, 0666) or die "can\'t mkfifo $path: $!";
 118 		Irssi::print("Fifo created. Start reading it (\"cat $path\") and try again.");
 119 		return;
 120 	    }
 121 	}
 122 	if (!sysopen(FIFO, $path, O_WRONLY | O_NONBLOCK)) { # or die "can't write $path: $!";
 123 		Irssi::print("Couldn\'t write to the fifo ($!). Please start reading the fifo (\"cat $path\") and try again.");
 124 		return;
 125 	}
 126 	FIFO->autoflush(1);
 127 	print FIFO "\033[2J\033[1;1H"; # erase screen & jump to 0,0
 128 	$cursor_line = 0;
 129 	if ($mode == $SCREEN) {
 130 		screen_stop();
 131 	}
 132 	$mode = $FIFO;
 133 	make_nicklist();
 134 }
 135 
 136 sub fifo_stop {
 137 	close FIFO;
 138 	$mode = $OFF;
 139 	Irssi::print("Fifo closed.");
 140 }
 141 
 142 ### screen ###
 143 
 144 sub cmd_screen_start {
 145 	if (!defined($ENV{'STY'})) {
 146 		Irssi::print 'screen not detected, screen mode only works inside screen';
 147 		return;
 148 	}
 149 	read_settings();
 150 	if ($mode == $SCREEN) {return;}
 151 	if ($mode == $FIFO) {
 152 		fifo_stop();
 153 	}
 154 	$mode = $SCREEN;
 155 	Irssi::signal_add_last('gui print text finished', \&sig_gui_print_text_finished);
 156 	Irssi::signal_add_last('gui page scrolled', \&sig_page_scrolled);
 157 	Irssi::signal_add('terminal resized', \&sig_terminal_resized);
 158 	screen_size();
 159 	make_nicklist();
 160 }
 161 
 162 sub screen_stop {
 163 	$mode = $OFF;
 164 	Irssi::signal_remove('gui print text finished', \&sig_gui_print_text_finished);
 165 	Irssi::signal_remove('gui page scrolled', \&sig_page_scrolled);
 166 	Irssi::signal_remove('terminal resized', \&sig_terminal_resized);
 167 	system 'screen -x '.$ENV{'STY'}.' -X fit';
 168 }
 169 
 170 sub screen_size {
 171 	if ($mode != $SCREEN) {
 172 		return;
 173 	}
 174 	$screen_resizing = 1;
 175 	# fit screen
 176 	system 'screen -x '.$ENV{'STY'}.' -X fit';
 177 	# get size (from perldoc -q size)
 178 	my ($winsize, $row, $col, $xpixel, $ypixel);
 179 	eval 'use Term::ReadKey; ($col, $row, $xpixel, $ypixel) = GetTerminalSize';
 180 	#	require Term::ReadKey 'GetTerminalSize';
 181 	#	($col, $row, $xpixel, $ypixel) = Term::ReadKey::GetTerminalSize;
 182 	#};
 183 	if ($@) { # no Term::ReadKey, try the ugly way
 184 		eval {
 185 			require 'sys/ioctl.ph';
 186 			# without this reloading doesn't work. workaround for some unknown bug
 187 			do 'asm/ioctls.ph';
 188 		};
 189 		
 190 		# ugly way not working, let's try something uglier, the dg-hack(tm) (constant for linux only?)
 191 		if($@) { no strict 'refs'; *TIOCGWINSZ = sub { return 0x5413 } }
 192 		
 193 		unless (defined &TIOCGWINSZ) {
 194 			die "Term::ReadKey not found, and ioctl 'workaround' failed. Install the Term::ReadKey perl module to use screen mode.\n";
 195 		}
 196 		open(TTY, "+</dev/tty") or die "No tty: $!";
 197 		unless (ioctl(TTY, &TIOCGWINSZ, $winsize='')) {
 198 			die "Term::ReadKey not found, and ioctl 'workaround' failed ($!). Install the Term::ReadKey perl module to use screen mode.\n";
 199 		}
 200 		close(TTY);
 201 		($row, $col, $xpixel, $ypixel) = unpack('S4', $winsize);
 202 	}
 203 	
 204 	# set screen width
 205 	$irssi_width = $col-$nicklist_width-1;
 206 	$height = $row-1;
 207 	
 208 	# on some recent systems, "screen -X fit; screen -X width -w 50" doesn't work, needs a sleep in between the 2 commands
 209 	# so we wait a second before setting the width
 210 	Irssi::timeout_add_once(1000, sub {
 211 		my ($new_irssi_width) = @_;
 212 		system 'screen -x '.$ENV{'STY'}.' -X width -w ' . $new_irssi_width;
 213 		# and then we wait another second for the resizing, and then redraw.
 214 		Irssi::timeout_add_once(1000,sub {$screen_resizing = 0; redraw()}, []);
 215 	}, $irssi_width);
 216 }
 217 
 218 sub sig_terminal_resized {
 219 	if ($screen_resizing) {
 220 		return;
 221 	}
 222 	$screen_resizing = 1;
 223 	Irssi::timeout_add_once(1000,\&screen_size,[]);
 224 }
 225 
 226 
 227 ### both ###
 228 
 229 sub nicklist_write_start {
 230 	if ($mode == $SCREEN) {
 231 		print STDERR "\033P\033[s\033\\"; # save cursor
 232 	}
 233 }
 234 
 235 sub nicklist_write_end {
 236 	if ($mode == $SCREEN) {
 237 		print STDERR "\033P\033[u\033\\"; # restore cursor
 238 	}
 239 }
 240 
 241 sub nicklist_write_line {
 242 	my ($line, $data) = @_;
 243 	if ($mode == $SCREEN) {
 244 		print STDERR "\033P\033[" . ($line+1) . ';'. ($irssi_width+1) .'H'. $screen_prefix . $data . "\033\\";
 245 	} elsif ($mode == $FIFO) {
 246 		$data = "\033[m$data"; # reset color
 247 		if ($line == $cursor_line+1) {
 248 			$data = "\n$data"; # next line
 249 		} elsif ($line == $cursor_line) {
 250 			$data = "\033[1G".$data; # back to beginning of line
 251 		} else {
 252 			$data = "\033[".($line+1).";0H".$data; # jump
 253 		}
 254 		$cursor_line=$line;
 255 		print(FIFO $data) or fifo_stop();
 256 	}
 257 }
 258 
 259 # recalc the text of the nicklist item
 260 sub calc_text {
 261 	my ($nick) = @_;
 262 	my $tmp = $nicklist_width-3;
 263 	(my $text = $nick->{'nick'}) =~ s/^(.{$tmp})..+$/$1\033[34m~\033[m/;
 264 	$nick->{'text'} = $prefix_mode[$nick->{'mode'}] . $text . (' ' x ($nicklist_width-length($nick->{'nick'})-1));
 265 	$nick->{'cmp'} = $nick->{'mode'}.lc($nick->{'nick'});
 266 }
 267 
 268 # redraw the given nick (nr) if it is visible
 269 sub redraw_nick_nr {
 270 	my ($nr) = @_;
 271 	my $line = $nr - $scroll_pos;
 272 	if ($line >= 0 && $line < $height) {
 273 		nicklist_write_line($line, $nicklist[$nr]->{'text'});
 274 	}
 275 }
 276 
 277 # nick was inserted, redraw area if necessary
 278 sub draw_insert_nick_nr {
 279 	my ($nr) = @_;
 280 	my $line = $nr - $scroll_pos;
 281 	if ($line < 0) { # nick is inserted above visible area
 282 		$scroll_pos++; # 'scroll' down :)
 283 	} elsif ($line < $height) { # line is visible
 284 		if ($mode == $SCREEN) {
 285 			need_redraw();
 286 		} elsif ($mode == $FIFO) {
 287 			my $data = "\033[m\033[L". $nicklist[$nr]->{'text'}; # reset color & insert line & write nick
 288 			if ($line == $cursor_line) {
 289 				$data = "\033[1G".$data; # back to beginning of line
 290 			} else {
 291 				$data = "\033[".($line+1).";1H".$data; # jump
 292 			}
 293 			$cursor_line=$line;
 294 			print(FIFO $data) or fifo_stop();
 295 			if ($prev_lines < $height) {
 296 				$prev_lines++; # the nicklist has one line more
 297 			}
 298 		}
 299 	}
 300 }
 301 
 302 sub draw_remove_nick_nr {
 303 	my ($nr) = @_;
 304 	my $line = $nr - $scroll_pos;
 305 	if ($line < 0) { # nick removed above visible area
 306 		$scroll_pos--; # 'scroll' up :)
 307 	} elsif ($line < $height) { # line is visible
 308 		if ($mode == $SCREEN) {
 309 			need_redraw();
 310 		} elsif ($mode == $FIFO) {
 311 			#my $data = "\033[m\033[L[i$line]". $nicklist[$nr]->{'text'}; # reset color & insert line & write nick
 312 			my $data = "\033[M"; # delete line
 313 			if ($line != $cursor_line) {
 314 				$data = "\033[".($line+1)."d".$data; # jump
 315 			}
 316 			$cursor_line=$line;
 317 			print(FIFO $data) or fifo_stop();
 318 			if (@nicklist-$scroll_pos >= $height) {
 319 				redraw_nick_nr($scroll_pos+$height-1);
 320 			}
 321 		}
 322 	}
 323 }
 324 
 325 # redraw the whole nicklist
 326 sub redraw {
 327 	$need_redraw = 0;
 328 	#make_nicklist();
 329 	nicklist_write_start();
 330 	my $line = 0;
 331 	### draw nicklist ###
 332 	for (my $i=$scroll_pos;$line < $height && $i < @nicklist; $i++) {
 333 		nicklist_write_line($line++, $nicklist[$i]->{'text'});
 334 	}
 335 
 336 	### clean up other lines ###
 337 	my $real_lines = $line;
 338 	while($line < $prev_lines) {
 339 		nicklist_write_line($line++,' ' x $nicklist_width);
 340 	}
 341 	$prev_lines = $real_lines;
 342 	nicklist_write_end();
 343 }
 344 
 345 # redraw (with little delay to avoid redrawing to much)
 346 sub need_redraw {
 347 	if(!$need_redraw) {
 348 		$need_redraw = 1;
 349 		Irssi::timeout_add_once(10,\&redraw,[]);
 350 	}
 351 }
 352 
 353 sub sig_page_scrolled {
 354 	$prev_lines = $height; # we'll need to redraw everything if he scrolled up
 355 	need_redraw;
 356 }
 357 
 358 # redraw (with delay) if the window is visible (only in screen mode)
 359 sub sig_gui_print_text_finished {
 360 	if ($need_redraw) { # there's already a redraw 'queued'
 361 		return;
 362 	}
 363 	my $window = @_[0];
 364 	if ($window->{'refnum'} == Irssi::active_win->{'refnum'} || Irssi::settings_get_str('nicklist_screen_split_windows') eq '*') {
 365 		need_redraw;
 366 		return;
 367 	}
 368 	foreach my $win (split(/[ ,]/, Irssi::settings_get_str('nicklist_screen_split_windows'))) {
 369 		if ($window->{'refnum'} == $win || $window->{'name'} eq $win) {
 370 			need_redraw;
 371 			return;
 372 		}
 373 	}
 374 }
 375 
 376 ####################
 377 ##### NICKLIST #####
 378 ####################
 379 
 380 # returns the position of the given nick(as string) in the (internal) nicklist
 381 sub find_nick {
 382 	my ($nick) = @_;
 383 	for (my $i=0;$i < @nicklist; $i++) {
 384 		if ($nicklist[$i]->{'nick'} eq $nick) {
 385 			return $i;
 386 		}
 387 	}
 388 	return -1;
 389 }
 390 
 391 # find position where nick should be inserted into the list
 392 sub find_insert_pos {
 393 	my ($cmp)= @_;
 394 	for (my $i=0;$i < @nicklist; $i++) {
 395 		if ($nicklist[$i]->{'cmp'} gt $cmp) {
 396 			return $i;
 397 		}
 398 	}
 399 	return scalar(@nicklist); #last
 400 }
 401 
 402 # make the (internal) nicklist (@nicklist)
 403 sub make_nicklist {
 404 	@nicklist = ();
 405 	$scroll_pos = 0;
 406 
 407 	### get & check channel ###
 408 	my $channel = Irssi::active_win->{active};
 409 
 410 	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'}) ) {
 411 		$active_channel = undef;
 412 		# no nicklist
 413 	} else {
 414 		$active_channel = $channel;
 415 		### make nicklist ###
 416 		my $thisnick;
 417 		foreach my $nick (sort {(($a->{'op'}?'1':$a->{'halfop'}?'2':$a->{'voice'}?'3':'4').lc($a->{'nick'}))
 418 		                    cmp (($b->{'op'}?'1':$b->{'halfop'}?'2':$b->{'voice'}?'3':'4').lc($b->{'nick'}))} $channel->nicks()) {
 419 			$thisnick = {'nick' => $nick->{'nick'}, 'mode' => ($nick->{'op'}?$MODE_OP:$nick->{'halfop'}?$MODE_HALFOP:$nick->{'voice'}?$MODE_VOICE:$MODE_NORMAL)};
 420 			calc_text($thisnick);
 421 			push @nicklist, $thisnick;
 422 		}
 423 	}
 424 	need_redraw();
 425 }
 426 
 427 # insert nick(as hash) into nicklist
 428 # pre: cmp has to be calculated
 429 sub insert_nick {
 430 	my ($nick) = @_;
 431 	my $nr = find_insert_pos($nick->{'cmp'});
 432 	splice @nicklist, $nr, 0, $nick;
 433 	draw_insert_nick_nr($nr);
 434 }
 435 
 436 # remove nick(as nr) from nicklist
 437 sub remove_nick {
 438 	my ($nr) = @_;
 439 	splice @nicklist, $nr, 1;
 440 	draw_remove_nick_nr($nr);
 441 }
 442 
 443 ###################
 444 ##### ACTIONS #####
 445 ###################
 446 
 447 # scroll the nicklist, arg = number of lines to scroll, positive = down, negative = up
 448 sub cmd_scroll {
 449 	if (!$active_channel) { # not a channel active
 450 		return;
 451 	}
 452 	my @nicks=Irssi::active_win->{active}->nicks;
 453 	my $nick_count = scalar(@nicks)+0;
 454 	my $channel = Irssi::active_win->{active};
 455 	if (!$channel || $channel->{type} ne 'CHANNEL' || !$channel->{names_got} || $nick_count <= Irssi::settings_get_int('nicklist_height')) {
 456 		return;
 457 	}
 458 	$scroll_pos += @_[0];
 459 
 460 	if ($scroll_pos > $nick_count - $height) {
 461 		$scroll_pos = $nick_count - $height;
 462 	}
 463 	if ($scroll_pos <= 0) {
 464 		$scroll_pos = 0;
 465 	}
 466 	need_redraw();
 467 }
 468 
 469 sub is_active_channel {
 470 	my ($server,$channel) = @_; # (channel as string)
 471 	return ($server && $server->{'tag'} eq $active_channel->{'server'}->{'tag'} && $server->channel_find($channel) && $active_channel && $server->channel_find($channel)->{'name'} eq $active_channel->{'name'});
 472 }
 473 
 474 sub sig_channel_wholist { # this is actualy a little late, when the names are received would be better
 475 	my ($channel) = @_;
 476 	if (Irssi::active_win->{'active'} && Irssi::active_win->{'active'}->{'name'} eq $channel->{'name'}) { # the channel joined is active
 477 		make_nicklist
 478 	}
 479 }
 480 
 481 sub sig_join {
 482 	my ($server,$channel,$nick,$address) = @_;
 483 	if (!is_active_channel($server,$channel)) {
 484 		return;
 485 	}
 486 	my $newnick = {'nick' => $nick, 'mode' => $MODE_NORMAL};
 487 	calc_text($newnick);
 488 	insert_nick($newnick);
 489 }
 490 
 491 sub sig_kick {
 492 	my ($server, $channel, $nick, $kicker, $address, $reason) = @_;
 493 	if (!is_active_channel($server,$channel)) {
 494 		return;
 495 	}
 496 	my $nr = find_nick($nick);
 497 	if ($nr == -1) {
 498 		Irssi::print("nicklist warning: $nick was kicked from $channel, but not found in nicklist");
 499 	} else {
 500 		remove_nick($nr);
 501 	}
 502 }
 503 
 504 sub sig_part {
 505 	my ($server,$channel,$nick,$address, $reason) = @_;
 506 	if (!is_active_channel($server,$channel)) {
 507 		return;
 508 	}
 509 	my $nr = find_nick($nick);
 510 	if ($nr == -1) {
 511 		Irssi::print("nicklist warning: $nick has parted $channel, but was not found in nicklist");
 512 	} else {
 513 		remove_nick($nr);
 514 	}
 515 
 516 }
 517 
 518 sub sig_quit {
 519 	my ($server,$nick,$address, $reason) = @_;
 520 	if ($server->{'tag'} ne $active_channel->{'server'}->{'tag'}) {
 521 		return;
 522 	}
 523 	my $nr = find_nick($nick);
 524 	if ($nr != -1) {
 525 		remove_nick($nr);
 526 	}
 527 }
 528 
 529 sub sig_nick {
 530 	my ($server, $newnick, $oldnick, $address) = @_;
 531 	if ($server->{'tag'} ne $active_channel->{'server'}->{'tag'}) {
 532 		return;
 533 	}
 534 	my $nr = find_nick($oldnick);
 535 	if ($nr != -1) { # if nick was found (nickchange is in current channel)
 536 		my $nick = $nicklist[$nr];
 537 		remove_nick($nr);
 538 		$nick->{'nick'} = $newnick;
 539 		calc_text($nick);
 540 		insert_nick($nick);
 541 	}
 542 }
 543 
 544 sub sig_mode {
 545 	my ($channel, $nick, $setby, $mode, $type) = @_; # (nick and channel as rec)
 546 	if ($channel->{'server'}->{'tag'} ne $active_channel->{'server'}->{'tag'} || $channel->{'name'} ne $active_channel->{'name'}) {
 547 		return;
 548 	}
 549 	my $nr = find_nick($nick->{'nick'});
 550 	if ($nr == -1) {
 551 		Irssi::print("nicklist warning: $nick->{'nick'} had mode set on $channel->{'name'}, but was not found in nicklist");
 552 	} else {
 553 		my $nicklist_item = $nicklist[$nr];
 554 		remove_nick($nr);
 555 		$nicklist_item->{'mode'} = ($nick->{'op'}?$MODE_OP:$nick->{'halfop'}?$MODE_HALFOP:$nick->{'voice'}?$MODE_VOICE:$MODE_NORMAL);
 556 		calc_text($nicklist_item);
 557 		insert_nick($nicklist_item);
 558 	}
 559 }
 560 
 561 ##### command binds #####
 562 Irssi::command_bind 'nicklist' => sub {
 563     my ( $data, $server, $item ) = @_;
 564     $data =~ s/\s+$//g;
 565     Irssi::command_runsub ('nicklist', $data, $server, $item ) ;
 566 };
 567 Irssi::signal_add_first 'default command nicklist' => sub {
 568 	# gets triggered if called with unknown subcommand
 569 	cmd_help();
 570 };
 571 Irssi::command_bind('nicklist update',\&update);
 572 Irssi::command_bind('nicklist help',\&cmd_help);
 573 Irssi::command_bind('nicklist scroll',\&cmd_scroll);
 574 Irssi::command_bind('nicklist fifo',\&cmd_fifo_start);
 575 Irssi::command_bind('nicklist screen',\&cmd_screen_start);
 576 Irssi::command_bind('nicklist screensize',\&screen_size);
 577 Irssi::command_bind('nicklist off',\&cmd_off);
 578 
 579 ##### signals #####
 580 Irssi::signal_add_last('window item changed', \&make_nicklist);
 581 Irssi::signal_add_last('window changed', \&make_nicklist);
 582 Irssi::signal_add_last('channel wholist', \&sig_channel_wholist);
 583 Irssi::signal_add_first('message join', \&sig_join); # first, to be before ignores
 584 Irssi::signal_add_first('message part', \&sig_part);
 585 Irssi::signal_add_first('message kick', \&sig_kick);
 586 Irssi::signal_add_first('message quit', \&sig_quit);
 587 Irssi::signal_add_first('message nick', \&sig_nick);
 588 Irssi::signal_add_first('message own_nick', \&sig_nick);
 589 Irssi::signal_add_first('nick mode changed', \&sig_mode);
 590 
 591 Irssi::signal_add('setup changed', \&read_settings);
 592 
 593 ##### settings #####
 594 Irssi::settings_add_str('nicklist', 'nicklist_screen_prefix', '\e[m ');
 595 Irssi::settings_add_str('nicklist', 'nicklist_prefix_mode_op', '\e[32m@\e[39m');
 596 Irssi::settings_add_str('nicklist', 'nicklist_prefix_mode_halfop', '\e[34m%\e[39m');
 597 Irssi::settings_add_str('nicklist', 'nicklist_prefix_mode_voice', '\e[33m+\e[39m');
 598 Irssi::settings_add_str('nicklist', 'nicklist_prefix_mode_normal', ' ');
 599 
 600 Irssi::settings_add_int('nicklist', 'nicklist_width',11);
 601 Irssi::settings_add_int('nicklist', 'nicklist_height',24);
 602 Irssi::settings_add_str('nicklist', 'nicklist_fifo_path', Irssi::get_irssi_dir . '/nicklistfifo');
 603 Irssi::settings_add_str('nicklist', 'nicklist_screen_split_windows', '');
 604 Irssi::settings_add_str('nicklist', 'nicklist_automode', '');
 605 
 606 read_settings();
 607 if (uc(Irssi::settings_get_str('nicklist_automode')) eq 'SCREEN') {
 608 	cmd_screen_start();
 609 } elsif (uc(Irssi::settings_get_str('nicklist_automode')) eq 'FIFO') {
 610 	cmd_fifo_start();
 611 }