nicklist.pl 18 KB

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