1# Operview - reformats some server notices, which may come i.e. from &clients
2# or &servers. Also reformat some incoming server numerics from advanced
3# commands like STATS.
4#
5# Note that whole this script is VERY ircnet-specific!
6#
7# Provided variables:
8#
9# mangle_stats_output   - turn the mangling of /stats output on/off
10# mangle_server_notices - turn the mangling of server notices on/off
11# ignore_server_kills   - we won't display nickname collissions
12# show_kills_path       - we will display kill's path
13#
14# $Id: operview.pl,v 1.11 2002/03/30 21:16:06 pasky Exp pasky $
15#
16
17
18use strict;
19use Irssi;
20use Irssi::Irc;
21use Irssi::TextUI;
22
23use vars qw ($VERSION %IRSSI $rcsid);
24
25$rcsid = '$Id: operview.pl,v 1.11 2002/03/30 21:16:06 pasky Exp pasky $';
26($VERSION) = '$Revision: 1.11 $' =~ / (\d+\.\d+) /;
27%IRSSI = (
28          name        => 'operview',
29          authors     => 'Petr Baudis',
30          contact     => 'pasky@ji.cz',
31          url         => 'http://pasky.ji.cz/~pasky/dev/irssi/',
32          license     => 'GPLv2, not later',
33          description => 'Reformats some server notices, which may come i.e. from &clients or &servers at IRCnet. You can turn the script on/off bytoggling variable mangle_server_notices.',
34          sbitems     => 'sclientcount kills',
35         );
36
37my $mangle_stats_output;
38my $mangle_server_notices;
39my $ignore_server_kills;
40my $show_kills_path;
41
42my @lastkill = ('','','');
43my @curclientcount = (0,0);
44
45Irssi::theme_register([
46  client_connect => '{servernotice $0}Connect    : {nick $[9]1} :: {nickhost $2%R@%n$3} {comment $4} :: $5-',
47  client_exit    => '{servernotice $0}Disconnect : {nick $[9]1} :: {nickhost $2%R@%n$3} :: $4-',
48  client_nick    => '{servernotice $0}{nick $[9]1} -> {nick $[9]2} :: {nickhost $3%R@%n$4}',
49  kills_kill     => '{servernotice $0}Received %gKILL%n {nick $[9]1} ({server $2}) :: $3', # TODO: parse the path? subject to change
50  kills_operkill => '{servernotice $0}Received %gKILL%n {nick $[9]1} (%R$2%n) :: $3',
51  kills_collide  => '{servernotice $0}Nick %gCOLLISION%n {nick $[9]1} :: $2',
52  servers_server => '{servernotice $0}Received %gSERVER%n {server $1} from {server $2} :: %G$3%w {comment $5} $6-',
53  servers_squit  => '{servernotice $0}Received %gSQUIT %n {server $1} from {server $2} :: %R$3-%w',
54  servers_sserver=> '{servernotice $0}Sending  %gSERVER%n {server $1} :: %G$2%w {comment $4} $5-',
55  servers_ssquit => '{servernotice $0}Sending  %gSQUIT %n {server $1} :: %R$2-%w',
56
57# TODO: Header ?               sendq         smsgs  skbs          rmsgs  rkbs      age
58  stats_l        => '$[!9]0 :: $[!7]3 %g<s%n $[!5]4 $[!5]5 %gr>%n $[!5]6 $[!5]7 :: $[!6]8 :: {nickhost $1%R@%n$2}',
59# TODO: Header ?                     pingf         connf         maxlinks      sendq         local limit               global limit
60  stats_y        => '$0 :: $[!4]1 :: %gpf%n $[!4]2 %gcf%n $[!4]3 %gml%n $[!4]4 %gsq%n $[!8]5 %gll%n $[!-2]6%K.%n$[!2]7 %ggl%n $[!-2]8%K.%n$[!2]9',
61# TODO: Header ?           haddr   hname      passwd    port     class
62  stats_i        => '$0 :: $[!20]1 $[!22]3 :: $[!6]2 :: %gp%n $4 %gc%n $5',
63# TODO: Header ?           port         class (N/A)     host                    reason
64  stats_k        => '$0 :: %gp%n $[!4]4 %gc%n $[!2]5 :: {nickhost $3%R@%n$1} :: $2',
65# TODO: Header ?           port/masklvl class           sname host                    passw
66  stats_c        => '$0 :: %gp%n $[!4]5 %gc%n $[!2]6 :: $4 :: {nickhost $1%R@%n$2} :: $3',
67  stats_n        => '$0 :: %gm%n $[!4]5 %gc%n $[!2]6 :: $4 :: {nickhost $1%R@%n$2} :: $3',
68
69# I wasn't able to discover how to get this working for statusbars. So THIS IS
70# NO-OP! Seek for its second incarnation hardcoded somewhere below.
71
72  sb_kill        => '{sb $0%R@%n$1}',
73  sb_operkill    => '{sb $0%R<%n$1}',
74  sb_collision   => '{sb $0%R!%n}',
75  sb_sclientcount=> '{sb $0%c/%n$1%cs%n}',
76]);
77
78
79sub event_server_notice {
80  my ($server, $data, $nick, $address) = @_;
81  my ($target, $text) = $data =~ /^(\S*)\s+:(.*)$/;
82  my (@text) = split(/ /, $text);
83
84  $show_kills_path = Irssi::settings_get_bool("show_kills_path");
85  $ignore_server_kills = Irssi::settings_get_bool("ignore_server_kills");
86  $mangle_server_notices = Irssi::settings_get_bool("mangle_server_notices");
87  return unless ($mangle_server_notices);
88
89  return if ($address or $nick !~ /\./);
90
91  if ($target eq '&CLIENTS') {
92
93    if ($text =~ /^Client connecting/) {
94      my (@fa) = ($text[2], $text[4], $text[6], $text[7], join(" ", splice(@text, 9)));
95
96      $fa[3] =~ s/^\[(.*)\]$/$1/;
97
98      $server->printformat($target, MSGLEVEL_SNOTES, "client_connect",
99	$nick, @fa);
100      Irssi::signal_stop();
101
102    } elsif ($text =~ /^Client exiting/) {
103      my (@fa) = ($text[2], $text[4], $text[6], join(" ", splice(@text, 8)));
104
105      $server->printformat($target, MSGLEVEL_SNOTES, "client_exit",
106	$nick, @fa);
107      Irssi::signal_stop();
108
109    } elsif ($text =~ /^Nick change/) {
110      my (@fa) = ($text[2], $text[4], $text[6], $text[8]);
111
112      $server->printformat($target, MSGLEVEL_SNOTES, "client_nick",
113	$nick, @fa);
114      Irssi::signal_stop();
115    }
116
117  } elsif ($target eq '&KILLS') {
118
119    if ($text =~ /^Received KILL/) {
120      my (@fa) = ($text[4], $text[6], join(" ", splice(@text, 9 - $show_kills_path)));
121
122      $fa[0] =~ s/\.$//;
123
124      if ($fa[1] =~ /\./) {
125        $server->printformat($target, MSGLEVEL_SNOTES, "kills_kill",
126                             $nick, @fa) unless ($ignore_server_kills);
127        @lastkill = ($fa[0], $fa[1], 's');
128      } else {
129        $server->printformat($target, MSGLEVEL_SNOTES+MSGLEVEL_HILIGHT, "kills_operkill",
130                             $nick, @fa);
131        @lastkill = ($fa[0], $fa[1], 'o');
132      }
133      refresh_kills();
134      Irssi::signal_stop();
135
136    } elsif ($text =~ /^Nick collision on/) {
137      my (@fa) = ($text[3], join(" ", splice(@text, 4)));
138
139      $server->printformat($target, MSGLEVEL_SNOTES, "kills_collide",
140			   $nick, @fa);
141      @lastkill = ($fa[0], '', 'c');
142
143      refresh_kills();
144      Irssi::signal_stop();
145    }
146
147  } elsif ($target eq '&NOTICES') {
148    if ($text =~ /^Local increase from/) {
149      @curclientcount = ($text[5], $text[8]);
150      refresh_sclientcount();
151    }
152
153  } elsif ($target eq '&SERVERS') {
154
155    if ($text =~ /^Received SERVER/) {
156      my ($sname) = join(" ", splice(@text, 5));
157      my (@fa) = ($text[2], $text[4],
158                  $sname =~ /^\((\d+)\s+(\[(.+?)\])?\s*(.*)\)$/);
159
160      $server->printformat($target, MSGLEVEL_SNOTES, "servers_server",
161	$nick, @fa);
162      Irssi::signal_stop();
163
164    } elsif ($text =~ /^Received SQUIT/) {
165      my (@fa) = ($text[2], $text[4], join(" ", splice(@text, 5)));
166
167      $fa[2] =~ s/^\((.*)\)$/$1/;
168
169      $server->printformat($target, MSGLEVEL_SNOTES, "servers_squit",
170	$nick, @fa);
171      Irssi::signal_stop();
172
173    } elsif ($text =~ /^Sending SERVER/) {
174      my ($sname) = join(" ", splice(@text, 3));
175      my (@fa) = ($text[2], $sname =~ /^\((\d+)\s+(\[(.+?)\])?\s*(.*)\)$/);
176
177      $server->printformat($target, MSGLEVEL_SNOTES, "servers_sserver",
178	$nick, @fa);
179      Irssi::signal_stop();
180
181    } elsif ($text =~ /^Sending SQUIT/) {
182      my (@fa) = ($text[2], join(" ", splice(@text, 3)));
183
184      $fa[1] =~ s/^\((.*)\)$/$1/;
185
186      $server->printformat($target, MSGLEVEL_SNOTES, "servers_ssquit",
187	$nick, @fa);
188      Irssi::signal_stop();
189    }
190
191  }
192}
193
194
195sub event_stats_numeric {
196  my ($server, $data, $srvname) = @_;
197  my ($target, $text) = $data =~ /^(\S*)\s+(.*)$/;
198  my (@text) = split(/ /, $text);
199  my ($num) = Irssi::signal_get_emitted() =~ /^event (\d+)$/;
200
201  $mangle_stats_output = Irssi::settings_get_bool("mangle_stats_output");
202  unless ($mangle_stats_output) {
203    Irssi::print $text, MSGLEVEL_CRAP;
204    return;
205  }
206
207  unless ($num) {
208    Irssi::print "[OperView] Internal error - emitted signal '".Irssi::signal_get_emitted()."' is not numerics event.";
209    return;
210  }
211
212#  Irssi::print "[$num][] $data -> $target , $text";
213
214  if ($num == 211) {
215# STATS L
216#:irc.cis.vutbr.cz 211 `asdf irc.cis.vutbr.cz[0.0.0.0@.3333] 0 92727331 1888902 168822985 3078358 :3201373
217#:irc.cis.vutbr.cz 211 `asdf irc.felk.cvut.cz[ircd@147.32.80.79] 6038 4876 52 268097 6375 :1427
218#:irc.cis.vutbr.cz 211 `asdf [unknown@66.135.66.250] 0 0 0 0 0 :0
219#:irc.cis.vutbr.cz 211 `asdf `asdf[~a@pasky.ji.cz] 478 2057 162 13 0 :324
220#:irc.cis.vutbr.cz 211 `asdf [@66.135.66.250] 0 10 0 11 0 :81
221#:irc.cis.vutbr.cz 211 `asdf `asdf[@62.44.12.54] 517 129 10 4 0 :87
222    my (@fa) = $text =~ /^(.*?)?\[([^[]*?)?@(.*?)\] (\d+) (\d+) (\d+) (\d+) (\d+) :(\d+)$/;
223
224    unless ($fa[2]) {
225      Irssi::print $text, MSGLEVEL_CRAP;
226    } else {
227      $server->printformat($target, MSGLEVEL_CRAP, "stats_l", @fa);
228    }
229    Irssi::signal_stop();
230
231  } elsif ($num == 218) {
232# STATS Y
233#:irc.cis.vutbr.cz 218 `asdf Y 0 120 600 1 384084 0.0 0.0
234#:irc.cis.vutbr.cz 218 `asdf Y 10 300 0 1 500000 1.1 1.1
235#:irc.cis.vutbr.cz 218 `asdf Y 12 300 0 10 700000 10.10 10.10
236#:irc.cis.vutbr.cz 218 `asdf Y 1 300 0 400 700000 10.3 10.3
237    my (@fa) = $text =~ /^(.) (\d+) (\d+) (\d+) (\d+) (\d+) (\d+)\.(\d+) :?(\d+)\.(\d+)$/;
238
239    unless ($fa[0]) {
240      Irssi::print $text, MSGLEVEL_CRAP;
241    } else {
242      $server->printformat($target, MSGLEVEL_CRAP, "stats_y", @fa);
243    }
244    Irssi::signal_stop();
245
246  } elsif ($num == 215) {
247# STATS I
248#:irc.cis.vutbr.cz 215 `asdf I pilsedu.cz <NULL> pilsedu.cz 0 12
249#:irc.cis.vutbr.cz 215 `asdf I x.opf.slu.cz <NULL> x.opf.slu.cz 0 9
250#:irc.cis.vutbr.cz 215 `asdf I 64.44.4.128/29 <NULL> <NULL> 0 1
251    my (@fa) = $text =~ /^(.) (\S+) (\S+) (\S+) (\d+) :?(\d+)$/;
252
253    unless ($fa[0]) {
254      Irssi::print $text, MSGLEVEL_CRAP;
255    } else {
256      $server->printformat($target, MSGLEVEL_CRAP, "stats_i", @fa);
257    }
258
259    Irssi::signal_stop();
260
261  } elsif ($num == 216) {
262# STATS K
263#:irc.cis.vutbr.cz 216 `asdf K *@*.*.*.*.*.*.*.*.* Access_denied,please_fix_your_domain_name * 0 -1
264#:irc.cis.vutbr.cz 216 `asdf K 195.116.4.* Access_denied,reason-use_servers_in_Poland * 0 -1
265#:irc.cis.vutbr.cz 216 `asdf K korak.isternet.sk abuse�-�expire�01.08.2003�16.26 * 0 -1
266#:irc.cis.vutbr.cz 216 `asdf K 193.84.192.0/24 compromissed�network�-�expire�05.04.2002�22.37 * 0 -1
267    my (@fa) = $text =~ /^(.) (\S+) (.+) (\S+) (\d+) :?([-0-9]+)$/;
268
269    unless ($fa[0]) {
270      Irssi::print $text, MSGLEVEL_CRAP;
271    } else {
272      $server->printformat($target, MSGLEVEL_CRAP, "stats_k", @fa);
273    }
274
275    Irssi::signal_stop();
276
277  } elsif ($num == 213) {
278# STATS C
279#:irc.cis.vutbr.cz 213 `asdf c *@129.143.67.242 * *.de 6666 6
280#:irc.cis.vutbr.cz 213 `asdf c *@141.24.101.9 * *.de 6667 6
281#:irc.cis.vutbr.cz 213 `asdf c *@131.174.124.200 * *.sci.kun.nl 6667 6
282#:irc.cis.vutbr.cz 213 `asdf c *@130.240.16.47 * *.se 6667 6
283#:irc.cis.vutbr.cz 213 `asdf c *@147.32.80.79 * irc.felk.cvut.cz 6664 6
284#:irc.cis.vutbr.cz 213 `asdf c *@195.146.134.62 * *.sk 0 2
285#:irc.cis.vutbr.cz 213 `asdf c *@195.168.1.141 * *.sk 0 2
286    my (@fa) = $text =~ /^(.) (\S+)@(\S+) (\S+) (\S+) ([.0-9]+) :?([-0-9]+)$/;
287
288    unless ($fa[0]) {
289      Irssi::print $text, MSGLEVEL_CRAP;
290    } else {
291      $server->printformat($target, MSGLEVEL_CRAP, "stats_c", @fa);
292    }
293
294    Irssi::signal_stop();
295
296  } elsif ($num == 214) {
297# (STATS N)
298#:irc.cis.vutbr.cz 214 `asdf N *@129.143.67.242 * *.de 0 6
299#:irc.cis.vutbr.cz 214 `asdf N *@141.24.101.9 * *.de 3 6
300#:irc.cis.vutbr.cz 214 `asdf N *@131.174.124.200 * *.sci.kun.nl 3 6
301#:irc.cis.vutbr.cz 214 `asdf N *@130.240.16.47 * *.se 3 6
302#:irc.cis.vutbr.cz 214 `asdf N *@147.32.80.79 * irc.felk.cvut.cz 0 6
303#:irc.cis.vutbr.cz 214 `asdf N *@195.146.134.62 * *.sk 3 2
304#:irc.cis.vutbr.cz 214 `asdf N *@195.168.1.141 * *.sk 3 2
305    my (@fa) = $text =~ /^(.) (\S+)@(\S+) (\S+) (\S+) (\d+) :?(\d+)$/;
306
307    unless ($fa[0]) {
308      Irssi::print $text, MSGLEVEL_CRAP;
309    } else {
310      $server->printformat($target, MSGLEVEL_CRAP, "stats_n", @fa);
311    }
312
313    Irssi::signal_stop();
314=brm
315  } elsif ($num == 250) {
316
317#TRACE
318#:irc.cis.vutbr.cz 204 `asdf Oper 12 pasky[~pasky@pasky.ji.cz]
319#:irc.cis.vutbr.cz 206 `asdf Serv 6 46S 95580C irc.felk.cvut.cz[ircd@147.32.80.79] *!*@irc.cis.vutbr.cz VFz
320#:irc.cis.vutbr.cz 205 `asdf User 1 `asdf[~a@pasky.ji.cz]
321#:irc.cis.vutbr.cz 262 `asdf irc.cis.vutbr.cz 2.10.3p3.addpl2.hemp. :End of TRACE
322#
323#STATS O
324#:irc.cis.vutbr.cz 243 `asdf O revisor@*.ssakhk.cz * erixon 0 10
325#:irc.cis.vutbr.cz 243 `asdf O cf@candyflip.junkie.cz * cf 0 12
326#:irc.cis.vutbr.cz 243 `asdf O *@pilsedu.cz * jv 0 12
327#:irc.cis.vutbr.cz 243 `asdf O *@62.44.12.54 * pasky 0 12
328#:irc.cis.vutbr.cz 243 `asdf O *@bsd.xcem.com * Krash 0 10
329#:irc.cis.vutbr.cz 243 `asdf O spike@*.pantexcom.com * Krash 0 10
330#:irc.cis.vutbr.cz 243 `asdf O fantomas@*.fantomas.sk * filozof 0 10
331#:irc.cis.vutbr.cz 243 `asdf O *@147.229.1.11 * StiX 0 10
332#:irc.cis.vutbr.cz 243 `asdf O *@160.216.0.0/16 * StiX 0 10
333#:irc.cis.vutbr.cz 219 `asdf O :End of STATS report
334
335# STATS H
336#:irc.cis.vutbr.cz 250 `asdf D *.fr.ircnet.net <NULL> * 0 0
337#:irc.cis.vutbr.cz 250 `asdf D *.belnet.be <NULL> * 0 0
338#:irc.cis.vutbr.cz 244 `asdf H * <NULL> irc.felk.cvut.cz 0 -1
339#:irc.cis.vutbr.cz 244 `asdf H * <NULL> *.de 0 -1
340#:irc.cis.vutbr.cz 244 `asdf H * <NULL> *.sci.kun.nl 0 -1
341#:irc.cis.vutbr.cz 244 `asdf H * <NULL> *.fi 0 -1
342#:irc.cis.vutbr.cz 244 `asdf H * <NULL> *.se 0 -1
343#:irc.cis.vutbr.cz 244 `asdf H * <NULL> *.sk 0 -1
344#:irc.cis.vutbr.cz 244 `asdf H * <NULL> irc.uhk.cz 0 -1
345#:irc.cis.vutbr.cz 219 `asdf H :End of STATS report
346    my (@fa) = $text =~ /^(.) (\S+)@(\S+) (\S+) (\S+) (\d+) :?(\d+)$/;
347
348    Irssi::print $text unless ($fa[0]);
349
350    $server->printformat($target, MSGLEVEL_CRAP, "stats_n",
351			 @fa);
352    Irssi::signal_stop();
353=cut
354  }
355}
356
357
358
359
360#
361### Statusbar stuff
362#
363
364
365sub sclientcount {
366  my ($item, $get_size_only) = @_;
367  my $f = '{sb '.$curclientcount[0].'%c/%n'.$curclientcount[1].'%cs%n}';
368
369  $item->default_handler($get_size_only, $f, undef, 1);
370}
371
372sub kills {
373  my ($item, $get_size_only) = @_;
374  my $theme = Irssi::current_theme();
375  my $f = '{sb %n}';
376
377  if ($lastkill[2] eq 's') {
378# Thanks to cras and darix for helping with following:
379# FIXME: Return value of following is for some reason "Perl script".
380#    $f = Irssi::active_win()->format_get_text("Irssi::Script::operview", Irssi::active_server(), undef, 'sb_kill', @lastkill);
381
382    $f = '{sb '.$lastkill[0].'%c@%n'.$lastkill[1].'}';
383  } elsif ($lastkill[2] eq 'o') {
384    $f = '{sb '.$lastkill[0].'%c<%n'.$lastkill[1].'}';
385  } elsif ($lastkill[2] eq 'c') {
386    $f = '{sb '.$lastkill[0].'%c!%n}';
387  }
388
389  $item->default_handler($get_size_only, $f, undef, 1);
390}
391
392
393sub refresh_sclientcount {
394  Irssi::statusbar_items_redraw('sclientcount');
395}
396
397sub refresh_kills {
398  Irssi::statusbar_items_redraw('kills');
399}
400
401
402Irssi::signal_add("event notice", "event_server_notice");
403Irssi::signal_add("event 211", "event_stats_numeric");
404Irssi::signal_add("event 213", "event_stats_numeric");
405Irssi::signal_add("event 214", "event_stats_numeric");
406Irssi::signal_add("event 215", "event_stats_numeric");
407Irssi::signal_add("event 216", "event_stats_numeric");
408Irssi::signal_add("event 218", "event_stats_numeric");
409#Irssi::signal_add("event 243", "event_stats_numeric");
410#Irssi::signal_add("event 244", "event_stats_numeric");
411#Irssi::signal_add("event 250", "event_stats_numeric");
412
413Irssi::settings_add_bool("lookandfeel", "mangle_stats_output", 0);
414Irssi::settings_add_bool("lookandfeel", "mangle_server_notices", 1);
415Irssi::settings_add_bool("lookandfeel", "ignore_server_kills", 0);
416Irssi::settings_add_bool("lookandfeel", "show_kills_path", 0);
417
418Irssi::statusbar_item_register("sclientcount", '$0', 'sclientcount');
419Irssi::statusbar_item_register("kills", '$0', 'kills');
420Irssi::statusbars_recreate_items();
421
422Irssi::print("OperView $VERSION loaded...");
423