html/monitor.pl


   1 #!/usr/bin/perl
   2 # Copyright (c) 2006 Jilles Tjoelker
   3 # All rights reserved.
   4 #
   5 # Redistribution and use in source and binary forms, with or without
   6 # modification, are permitted provided that the following conditions
   7 # are met:
   8 # 1. Redistributions of source code must retain the above copyright
   9 #    notice, this list of conditions and the following disclaimer.
  10 # 2. Redistributions in binary form must reproduce the above copyright
  11 #    notice, this list of conditions and the following disclaimer in the
  12 #    documentation and/or other materials provided with the distribution.
  13 #
  14 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  15 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  16 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  17 # ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  18 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  19 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  20 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  21 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  22 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  23 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  24 # SUCH DAMAGE.
  25 
  26 use strict;
  27 use Irssi;
  28 use vars qw($VERSION %IRSSI);
  29 
  30 $VERSION = "1.0";
  31 
  32 %IRSSI = (
  33     authors    => "Jilles Tjoelker",
  34     contact    => "jilles\@stack.nl",
  35     name       => "monitor",
  36     description=> "Interface to ratbox 2.1+ /monitor command",
  37     license    => "BSD (revised)",
  38 );
  39 
  40 # Track the nicks in our monitor list
  41 my %monitorlist;
  42 # Server::connect_time we added monitor items
  43 my %readded;
  44 # Nicks waiting on /accept
  45 my %acceptqueue;
  46 
  47 Irssi::theme_register([monitoron => 'Now online: {nick $0} {nickhost $1}',
  48 	monitoroff => 'Now offline: {nick $0} {nickhost $1} {comment $2}',
  49 	monitorlist => 'Monitored: $0',
  50 	monitordel => 'No longer monitoring: $0',
  51 	monitoralready => 'Already monitoring: $0']);
  52 
  53 sub event_motdgot {
  54 	my ($server, $args, $nick, $address) = @_;
  55 
  56 	if ($readded{$server->{tag}} != $server->{connect_time}) {
  57 		Irssi::print("Readding monitor items");
  58 		cmd_monitor_readd('', $server, undef);
  59 	}
  60 }
  61 
  62 sub doaccept {
  63 	my $server = shift;
  64 
  65 	if (defined $server->isupport("CALLERID")) {
  66 		$server->print('','Accepting '.$acceptqueue{$server->{tag}});
  67 		$server->command("QUOTE ACCEPT ".$acceptqueue{$server->{tag}});
  68 	} else {
  69 		$server->print('','Not accepting '.$acceptqueue{$server->{tag}}.', server does not support callerid');
  70 	}
  71 	$acceptqueue{$server->{tag}} = '';
  72 }
  73 
  74 sub nowonline {
  75 	my ($server, $nuh) = @_;
  76 	my ($n, $uh) = split /!/, $nuh, 2;
  77 	my $ln = lc $n;
  78 
  79 	$server->printformat('', MSGLEVEL_CLIENTCRAP, 'monitoron', $n, $uh);
  80 	$monitorlist{$server->{tag}}{$ln}{lastseen} = time();
  81 	if ($monitorlist{$server->{tag}}{$ln}{action} eq 'accept') {
  82 		if ($acceptqueue{$server->{tag}} eq '') {
  83 			Irssi::timeout_add_once(3000, 'doaccept', $server);
  84 			$acceptqueue{$server->{tag}} = $n;
  85 		} else {
  86 			$acceptqueue{$server->{tag}} .= ','.$n;
  87 		}
  88 	}
  89 }
  90 
  91 sub event_mononline {
  92 	my ($server, $args, $nick, $address) = @_;
  93 	my @a = split(/ +/, $args);
  94 	my ($nuh, $n, $addr, $ln);
  95 # :jaguar.test 730 jilles :n!u@h,n2!u@h
  96 	$a[1] =~ s/^://;
  97 	foreach $nuh (split /,/, $a[1]) {
  98 		($n, $addr) = split /!/, $nuh;
  99 		$ln = lc $n;
 100 		$monitorlist{$server->{tag}}{$ln}{address} = $addr;
 101 		$monitorlist{$server->{tag}}{$ln}{nick_online} = 1;
 102 		$monitorlist{$server->{tag}}{$ln}{mask_online} = $server->masks_match($monitorlist{$server->{tag}}{$ln}{masks}, $n, $addr);
 103 		if ($monitorlist{$server->{tag}}{$ln}{mask_online}) {
 104 			nowonline($server, $nuh);
 105 		} elsif ($monitorlist{$server->{tag}}{$ln}{new}) {
 106 			$server->printformat('', MSGLEVEL_CLIENTCRAP, 'monitoroff', $n, '');
 107 		}
 108 		$monitorlist{$server->{tag}}{$ln}{new} = 0;
 109 	}
 110 	Irssi::signal_stop();
 111 }
 112 
 113 sub event_monoffline {
 114 	my ($server, $args, $nick, $address) = @_;
 115 	my @a = split(/ +/, $args);
 116 	my ($n, $ln);
 117 # :jaguar.test 731 jilles :n,n2
 118 	$a[1] =~ s/^://;
 119 	foreach $n (split /,/, $a[1]) {
 120 		$ln = lc $n;
 121 		if ($monitorlist{$server->{tag}}{$ln}{mask_online} || $monitorlist{$server->{tag}}{$ln}{new}) {
 122 			if ($monitorlist{$server->{tag}}{$ln}{nick_online}) {
 123 				$server->printformat('', MSGLEVEL_CLIENTCRAP, 'monitoroff', $n, $monitorlist{$server->{tag}}{$ln}{address});
 124 			} else {
 125 				$server->printformat('', MSGLEVEL_CLIENTCRAP, 'monitoroff', $n, '');
 126 			}
 127 			$monitorlist{$server->{tag}}{$ln}{lastseen} = time() if $monitorlist{$server->{tag}}{$ln}{mask_online};
 128 			$monitorlist{$server->{tag}}{$ln}{mask_online} = 0;
 129 			$monitorlist{$server->{tag}}{$ln}{new} = 0;
 130 		}
 131 		$monitorlist{$server->{tag}}{$ln}{nick_online} = 0;
 132 	}
 133 	Irssi::signal_stop();
 134 }
 135 
 136 sub event_monlist {
 137 	my @a = split(/ +/, $_[1]);
 138 # :jaguar.test 732 jilles :n,n2
 139 	$a[1] =~ s/^://;
 140 	$a[1] =~ s/,/ /g;
 141 	$_[0]->printformat('', MSGLEVEL_CLIENTCRAP, 'monitorlist', $a[1]);
 142 	Irssi::signal_stop();
 143 }
 144 
 145 sub cmd_monitor {
 146 	my ($data, $server, $item) = @_;
 147 
 148 	if ($data ne '') {
 149 		Irssi::command_runsub ('monitor', $data, $server, $item);
 150 	} else {
 151 		cmd_monitor_show(@_);
 152 	}
 153 }
 154 
 155 sub cmd_monitor_add {
 156 	my ($data, $server, $item) = @_;
 157 	my @nicks;
 158 	my $data2;
 159 	my $nuh;
 160 	my ($n, $ln);
 161 	my ($doaction, $action) = (0, '');
 162 
 163 	if (!defined $server->isupport("MONITOR")) {
 164 		$server->print('', "No monitor support");
 165 		return;
 166 	}
 167 
 168 	if ($data =~ /-([^ ]*) (.*)/) {
 169 		$doaction = 1;
 170 		$action = $1;
 171 		$data = $2;
 172 	}
 173 	$data =~ s/ /,/g;
 174 	@nicks = split /,/, $data;
 175 	$data2 = '';
 176 	foreach $nuh (@nicks) {
 177 		$n = $nuh;
 178 		$n =~ s/!.*//;
 179 		next if $n eq '';
 180 		if ($n eq $nuh) {
 181 			$nuh .= '!*@*';
 182 		}
 183 		$ln = lc $n;
 184 		if (defined($monitorlist{$server->{tag}}{$ln})) {
 185 			if ($doaction) {
 186 				$monitorlist{$server->{tag}}{$ln}{action} = $action;
 187 			}
 188 			my $m = ' '.$monitorlist{$server->{tag}}{$ln}{masks}.' ';
 189 			if ($m =~ / \Q$nuh\E /) {
 190 				$server->printformat('', MSGLEVEL_CLIENTCRAP, 'monitoralready', $nuh);
 191 				next;
 192 			}
 193 			$monitorlist{$server->{tag}}{$ln}{masks} .= ' '.$nuh;
 194 			if ($monitorlist{$server->{tag}}{$ln}{nick_online} &&
 195 				!$monitorlist{$server->{tag}}{$ln}{mask_online})
 196 			{
 197 				if ($server->mask_match_address($nuh, $n, $monitorlist{$server->{tag}}{$ln}{address}))
 198 				{
 199 					$monitorlist{$server->{tag}}{$ln}{mask_online} = 1;
 200 					nowonline($server, $n.'!'.$monitorlist{$server->{tag}}{$ln}{address});
 201 				}
 202 			}
 203 		} else {
 204 			$data2 .= ','.$n;
 205 			$monitorlist{$server->{tag}}{$ln}{masks} = $nuh;
 206 			$monitorlist{$server->{tag}}{$ln}{nick_online} = 0;
 207 			$monitorlist{$server->{tag}}{$ln}{mask_online} = 0;
 208 			$monitorlist{$server->{tag}}{$ln}{action} = $action;
 209 			$monitorlist{$server->{tag}}{$ln}{lastseen} = 0;
 210 			$monitorlist{$server->{tag}}{$ln}{new} = 1;
 211 		}
 212 	}
 213 	$data2 =~ s/^,//;
 214 	return if ($data2 eq '');
 215 	$server->command("QUOTE MONITOR + $data2");
 216 }
 217 
 218 sub cmd_monitor_readd {
 219 	my ($data, $server, $item) = @_;
 220 	my ($n, $data2);
 221 	
 222 	$readded{$server->{tag}} = $server->{connect_time};
 223 	$data2 = '';
 224 	foreach $n (keys %{$monitorlist{$server->{tag}}}) {
 225 		$data2 .= ','.$n;
 226 	}
 227 	$data2 =~ s/^,//;
 228 	return if ($data2 eq '');
 229 	if (!defined $server->isupport("MONITOR")) {
 230 		$server->print('', "No monitor support");
 231 		return;
 232 	}
 233 	$server->command("QUOTE MONITOR + $data2");
 234 }
 235 
 236 sub cmd_monitor_clear {
 237 	my ($data, $server, $item) = @_;
 238 	$monitorlist{$server->{tag}} = ();
 239 	$server->printformat('', MSGLEVEL_CLIENTCRAP, 'monitordel', '*');
 240 	if (defined $server->isupport("MONITOR")) {
 241 		$server->command("QUOTE MONITOR C");
 242 	}
 243 }
 244 
 245 sub cmd_monitor_delete {
 246 	my ($data, $server, $item) = @_;
 247 	my @nicks;
 248 	my $data2;
 249 	my $data3;
 250 	my $nuh;
 251 	my ($n, $ln);
 252 
 253 	$data =~ s/ /,/g;
 254 	@nicks = split /,/, $data;
 255 	$data2 = '';
 256 	$data3 = '';
 257 	foreach $nuh (@nicks) {
 258 		$n = $nuh;
 259 		$n =~ s/!.*//;
 260 		next if $n eq '';
 261 		$ln = lc $n;
 262 		next unless (defined($monitorlist{$server->{tag}}{$ln}));
 263 		if ($n ne $nuh) {
 264 			my $m = ' '.$monitorlist{$server->{tag}}{$ln}{masks}.' ';
 265 			next unless ($m =~ s/ \Q$nuh\E / /);
 266 			$m =~ s/^ //;
 267 			$m =~ s/ $//;
 268 			$monitorlist{$server->{tag}}{$ln}{masks} = $m;
 269 			if ($m ne '') {
 270 				if ($monitorlist{$server->{tag}}{$ln}{mask_online}) {
 271 					$monitorlist{$server->{tag}}{$ln}{mask_online} = $server->masks_match($monitorlist{$server->{tag}}{$ln}{masks}, $n, $monitorlist{$server->{tag}}{$ln}{address});
 272 					if (!$monitorlist{$server->{tag}}{$ln}{mask_online}) {
 273 						$server->printformat('', MSGLEVEL_CLIENTCRAP, 'monitoroff', $n, '');
 274 					}
 275 				}
 276 				$data3 .= $nuh.' ';
 277 				next;
 278 			}
 279 		}
 280 		$data3 .= $n.' ';
 281 		delete $monitorlist{$server->{tag}}{$ln};
 282 		$data2 .= ','.$n;
 283 	}
 284 	$data2 =~ s/^,//;
 285 	$server->printformat('', MSGLEVEL_CLIENTCRAP, 'monitordel', $data3);
 286 	return if ($data2 eq '');
 287 	#$server->printformat('', MSGLEVEL_CLIENTCRAP, 'monitordel', $data2);
 288 	if (defined $server->isupport("MONITOR")) {
 289 		$server->command("QUOTE MONITOR - $data2");
 290 	}
 291 }
 292 
 293 sub cmd_monitor_list {
 294 	my ($data, $server, $item) = @_;
 295 	my ($n, $ln);
 296 	my $count = 0;
 297 	my $misc;
 298 	my $lastseen;
 299 
 300 	foreach $n (keys %{$monitorlist{$server->{tag}}}) {
 301 		$ln = lc $n;
 302 		$misc = 'masks: '.$monitorlist{$server->{tag}}{$ln}->{masks};
 303 		if ($monitorlist{$server->{tag}}{$ln}->{action}) {
 304 			$misc .= ', action: '.$monitorlist{$server->{tag}}{$ln}->{action};
 305 		}
 306 		if ($monitorlist{$server->{tag}}{$ln}{mask_online}) {
 307 			$server->printformat('', MSGLEVEL_CLIENTCRAP, 'monitorlist', $n.' ('.$monitorlist{$server->{tag}}{$ln}->{address}.'), '.$misc);
 308 		} else {
 309 			if ($monitorlist{$server->{tag}}{$ln}{lastseen}) {
 310 				$lastseen = localtime($monitorlist{$server->{tag}}{$ln}{lastseen});
 311 			} else {
 312 				$lastseen = "never";
 313 			}
 314 			$server->printformat('', MSGLEVEL_CLIENTCRAP, 'monitorlist', $n.', '.$misc.', lastseen: '.$lastseen.', lastaddr: '.$monitorlist{$server->{tag}}{$ln}->{address});
 315 		}
 316 		$count++;
 317 	}
 318 	if ($count == 0) {
 319 		Irssi::print("Monitor list for ".$server->{tag}." is empty");
 320 	}
 321 	#$server->command("QUOTE MONITOR L");
 322 }
 323 
 324 sub cmd_monitor_show {
 325 	my ($data, $server, $item) = @_;
 326 	my ($n, $ln);
 327 	my $count = 0;
 328 	my $lastseen;
 329 
 330 	foreach $n (keys %{$monitorlist{$server->{tag}}}) {
 331 		$ln = lc $n;
 332 		if ($monitorlist{$server->{tag}}{$ln}{mask_online}) {
 333 			$server->printformat('', MSGLEVEL_CLIENTCRAP, 'monitoron', $n, $monitorlist{$server->{tag}}{$n}->{address});
 334 		} else {
 335 			if ($monitorlist{$server->{tag}}{$n}{lastseen}) {
 336 				$lastseen = localtime($monitorlist{$server->{tag}}{$n}{lastseen});
 337 			} else {
 338 				$lastseen = "never";
 339 			}
 340 			$server->printformat('', MSGLEVEL_CLIENTCRAP, 'monitoroff', $n, '', 'last seen: '.$lastseen);
 341 		}
 342 		$count++;
 343 	}
 344 	if ($count == 0) {
 345 		Irssi::print("Monitor list for ".$server->{tag}." is empty");
 346 	}
 347 	#$server->command("QUOTE MONITOR S");
 348 }
 349 
 350 sub cmd_monitor_save {
 351 	#my ($data, $server, $item) = @_;
 352 	my $file = Irssi::get_irssi_dir."/monitor";
 353 	my ($net, $n, $k);
 354 	open FILE, "> $file" or return;
 355 	foreach $net (keys %monitorlist) {
 356 		foreach $n (keys %{$monitorlist{$net}}) {
 357 			$monitorlist{$net}{$n}{lastseen} = time() if $monitorlist{$net}{$n}{mask_online};
 358 			foreach $k (keys %{$monitorlist{$net}{$n}}) {
 359 				next if ($k eq 'mask_online' || $k eq 'nick_online' || $k eq 'new');
 360 				printf FILE ("%s %s %s %s\n", $net, $n, $k, $monitorlist{$net}{$n}{$k});
 361 			}
 362 		}
 363 	}
 364 	close FILE;
 365 	Irssi::print("Monitor list saved to $file");
 366 }
 367 
 368 sub cmd_monitor_load {
 369 	#my ($data, $server, $item) = @_;
 370 	my $file = Irssi::get_irssi_dir."/monitor";
 371 
 372 	open FILE, "< $file" or return;
 373 	%monitorlist = ();
 374 	while (<FILE>) {
 375 		chomp;
 376 		my ($net, $n, $k, $value) = split (/ /, $_, 4);
 377 		$monitorlist{$net}{lc $n}{$k} = $value;
 378 	}
 379 	close FILE;
 380 	Irssi::print("Monitor list loaded from $file");
 381 }
 382 
 383 sub cmd_monitor_help {
 384 	#my ($data, $server, $item) = @_;
 385 
 386 	Irssi::print(
 387 "%CNotify list using MONITOR extension%n\n".
 388 "This script provides a notify list using the MONITOR extension found ".
 389 "in ratbox 2.1 and newer and charybdis (MONITOR keyword in 005 numeric).\n".
 390 "Each server tag has its own list.\n\n".
 391 "COMMANDS:\n\n".
 392 "%_/MONITOR ADD [-|-accept] nick[!user\@host]...%_\n".
 393 "  - Adds nicks/hostmasks or changes their accept setting, for this server. ".
 394 "The nick cannot contain wildcards but the user\@host can. ".
 395 "If the user\@host part is omitted, *@* is used. ".
 396 "A - disables accept for the given nicks, a -accept enables it.\n".
 397 "%_/MONITOR DEL nick[!user\@host]...%_\n".
 398 "  - Deletes nicks/hostmasks for this server. If a user\@host is given, that ".
 399 "user\@host is deleted and the whole nick if it was the last, otherwise the ".
 400 "whole nick.\n".
 401 "%_/MONITOR CLEAR%_\n".
 402 "  - Clears the monitor list for this server.\n".
 403 "%_/MONITOR [SHOW]%_\n".
 404 "  - Shows the monitor list for this server in a brief format.\n".
 405 "%_/MONITOR LIST%_\n".
 406 "  - Shows the monitor list for this server in a long format.\n".
 407 "%_/MONITOR LOAD%_\n".
 408 "  - Reloads the monitor list for all servers from ~/.irssi/monitor. ".
 409 "The lists on the servers are not updated.\n".
 410 "%_/MONITOR SAVE%_\n".
 411 "  - Saves the monitor list for all servers to ~/.irssi/monitor.\n".
 412 "%_/MONITOR READD%_\n".
 413 "  - Adds the known entries to the server-side list, for this server. ".
 414 "This is normally done automatically when the MOTD is received.\n".
 415 "\nAfter a reload of the script it may be necessary to do /foreach server /quote monitor s.".
 416 "", MSGLEVEL_CLIENTCRAP);
 417 }
 418 
 419 Irssi::signal_add('event 376', 'event_motdgot');
 420 Irssi::signal_add('event 422', 'event_motdgot');
 421 Irssi::signal_add('event 730', 'event_mononline');
 422 Irssi::signal_add('event 731', 'event_monoffline');
 423 Irssi::signal_add('event 732', 'event_monlist');
 424 #Irssi::signal_add('event 733', 'event_endofmonlist');
 425 #Irssi::signal_add('event 734', 'event_monlistfull');
 426 
 427 Irssi::signal_add_last('setup saved', 'cmd_monitor_save');
 428 Irssi::signal_add_last('setup reread', 'cmd_monitor_load');
 429 
 430 Irssi::command_bind('monitor', 'cmd_monitor');
 431 Irssi::command_bind('monitor add', 'cmd_monitor_add');
 432 Irssi::command_bind('monitor readd', 'cmd_monitor_readd');
 433 Irssi::command_bind('monitor clear', 'cmd_monitor_clear');
 434 Irssi::command_bind('monitor delete', 'cmd_monitor_delete');
 435 Irssi::command_bind('monitor list', 'cmd_monitor_list');
 436 Irssi::command_bind('monitor show', 'cmd_monitor_show');
 437 Irssi::command_bind('monitor save', 'cmd_monitor_save');
 438 Irssi::command_bind('monitor load', 'cmd_monitor_load');
 439 Irssi::command_bind('monitor help', 'cmd_monitor_help');
 440 
 441 cmd_monitor_load();