use Irssi;
use strict;

use vars qw($VERSION %IRSSI);

my %Ignore = (
	nickserv_kills	=> 1,
	kills			=> 1,
	klines			=> 1,
	routing			=> 0,
);

$VERSION = '20030719';
%IRSSI = (
	authors		=> 'Marco d\'Itri',
	contact		=> 'md@linux.it',
	name		=> 'ircop',
	description	=> 'things useful to ircops',
	license		=> 'GPL v2',
	url			=> 'http://www.linux.it/~md/irssi/',
);

#-----------------------------------------------------------------------------
Irssi::theme_register([
	my_notice_server	=> '{servernotice $0}$1',
	my_wallops			=> '%K-%m($1)%M$0%K-%n $2-',
]);

Irssi::signal_add('event 376'		=> 'event_connect');	# RPL_ENDOFMOTD
Irssi::signal_add('event 422'		=> 'event_connect');	# ERR_NOMOTD
Irssi::signal_add('event 433'		=> 'event_nick_taken');	# ERR_NICKNAMEINUSE
Irssi::signal_add('event 381'		=> 'event_oper');		# RPL_YOUREOPER
Irssi::signal_add('event notice'	=> 'event_notice');
Irssi::signal_add('event wallops'	=> 'event_wallops');

Irssi::command_bind_last('join'		=> 'encoded_join');
Irssi::command_bind(kline			=> 'cmd_kline');
Irssi::command_bind(oconnect		=> 'cmd_oconnect');
Irssi::command_bind(sconnect		=> 'no_sconnect');

my %split_from;

if (not Irssi::window_find_name('snotices')) {
	Irssi::print('Please create a window named snotices');
#	Irssi::command('window new hide');
#	Irssi::command('window name snotices');
#	Irssi::command('window move 99');	# far left
}

my ($NickPass, $OperPass) = read_pwds($ENV{HOME} . '/.irssi/.operpass');
#-----------------------------------------------------------------------------
sub event_connect {
	my ($server, $data, $source, $source_mask) = @_;
	my ($target, $msg) = $data =~ /^(\S*)\s:(.*)/;

	return if $source !~ /calvino\.freenode\.net$/;

	$server->send_raw("NickServ identify $NickPass")
		if $NickPass and $target eq 'Md';
	$server->send_raw("OperServ identify $OperPass")
		if $OperPass and $target eq 'Md';
	$server->send_raw("OPER Md $OperPass") if $OperPass;

#	Irssi::print(">$target<>$msg<>$source<>$source_mask");
	$server->send_raw("mode $target +12mw");
}

sub event_nick_taken {
	my ($server, $data, $source, $source_mask) = @_;
	my ($target, $msg) = $data =~ /^(\S*)\s:(.*)/;

	Irssi::print("### >$target<>$msg<>$source<>$source_mask< [NICK TAKEN]");
	return if $source !~ /calvino\.freenode\.net$/;
	return if not $NickPass;

	$server->send_raw("NickServ ghost Md $NickPass");
	sleep 1; # XXX
	$server->send_raw("NICK Md");
}

sub event_oper {
	my ($server, $data, $source, $source_mask) = @_;
	my ($target, $msg) = $data =~ /^(\S*)\s:(.*)/;

	Irssi::print("### you are now opered ###");
#	$server->send_raw("mode $target +w");
}

sub event_notice {
	my ($server, $data, $source, $source_mask) = @_;

	return if $source_mask;		# not a server notice

	my ($target, $msg) = $data =~ /^(\S*)\s:(.*)/;
	local $_ = $msg;
	s/^\*\*\* Notice -- //;

# splitserver.openprojects.net was connected to hubserver.openprojects.net for 192612 seconds.  31359/1709 sendK/recvK. (Remote closed the connection)

	if (/(\S+) was connected to (\S+) for (\d+) seconds.+\((.+)\)$/) {
		Irssi::print("=====> $1 disconnected from $2 ($3s, $4)") if $3 > 180;
		$split_from{$1} = $2;
	}

	Irssi::signal_stop();

	return if (
		/^Kick from/ or
		/^Remove from/ or
		/^Flooder.*nick\)$/ or
		/^\S+ has removed the K-Line/ or
		/^\S+ \S+ just activated an O:line/ or
		/^DUP: K: / or
		/^X-line Warning/ or	 # +f
		/^Write error to .*, closing link$/ or
		/^CHALL received, trying to use N:line/ or
#		/^\S+ had been connected for / or
		/^\S+ had been connected for / or
		/^Server \S+ closed the connection/ or
		/^Added K-Line [\S+] to \S+\/kline.conf$/ or
#		/^Link \[unknown@255\.255\.255\.255\] cancelled, server services\. already exists/ or
		/255\.255\.255\.255.* server services\. already exists/ or
		$Ignore{nickserv_kills} and (
			/^Received KILL message for \S+\. From NickServ/ or
			/^Received KILL message for \S+\. From services/ or			
			/^Ghosted:/
		) or
		$Ignore{kills} and (
			/^Nick change collision from/ or
			/^Killing \S+ for / or
			/^\S+ confirms kill of/	or			# +k
			/^\S+ confirms D-line of/			# +k
		) or
		$Ignore{klines} and (
			/^added D-Line for \[.+\] \[Auto-dline channel/ or
			/^(?:proxyscan|chii|lilo`|d?micah.*) added K-Line for / or
			#/^\S+ added K-Line for/
			/^Expiring K:line/ #or
		) or
		$Ignore{routing} and (
			/^\S+ was connected to \S+ for/ or
			/^CONNECT/ or
			/Write error to \S+, closing link/ or
			/Got a good password response from/ or
			/Link with \S+ established:/ or
			/Link \S+ notable TS delta/
		)
	);

	my $window = Irssi::window_find_name('snotices') || Irssi::active_win();
	$source =~ s/\.freenode\.net$//;
	$window->printformat(MSGLEVEL_NOTICES, 'my_notice_server', $source, $_);
}

sub event_wallops {
	my ($server, $data, $source, $source_mask) = @_;
	my ($type, $msg) = $data =~ /^:(?:([A-Z]+) - )?(.*)/;
	$type ||= 'WALLOP';

	my $window = Irssi::active_win();
	$window->printformat(MSGLEVEL_WALLOPS, 'my_wallops', $source, $type, $msg);
	Irssi::signal_stop();
}

sub read_pwds {
	my ($file) = @_;

	if (not open(PASSFILE, $ENV{HOME} . '/.irssi/.operpass')) {
		Irssi::print("Cannot read operator password from $file: $!");
		return;
	}
	my @pw = <PASSFILE>;
	close PASSFILE;
	chomp @pw;
	return @pw;
}

sub encoded_join {
	my ($params, $server) = @_;

	my @params = split(/\s+/, $params);
	return if @params != 1;				# not a simple /join #channel

	my $channel = $params[0];
	$channel =~ s/\\x([\da-fA-F]{2})/ pack('C', hex($1)) /eg;
	$server->send_raw("JOIN :$channel");
	Irssi::signal_stop;
}

sub cmd_kline {
	my ($params, $server, $winit) = @_;

	my ($who, $length, $reason) = split(/\s+/, $params, 3);
	if (not (defined $who and defined $length) or $who =~ /^\d+$/) {
		Irssi::print('Usage: /kline user@host [LENGTH (14 D)] reason');
		return;
	}
	if ($length =~ /^(\d+)([hHdD]?)$/) {
		$length = $1;
		my $unit = lc $2;
		if    ($unit eq 'h') { $length *= 60; }
		elsif ($unit eq 'd') { $length *= 60 * 24; }
	} else {
		$reason = $length . ' ' . $reason; $reason =~ s/ +$//;
		$length = 60 * 24 * 2;	# default length: 2 days
	}
	$who = '*@' . $who if $who =~ /[\.:]/ and $who !~ /@/;

	if ($length == 0) {
		$server->send_raw("KLINE $who :$reason");
	} else {
		$server->send_raw("KLINE $length $who :$reason");
	}
}

sub cmd_oconnect {
	my ($params, $server, $winit) = @_;

	my ($to, $from, $extra) = split(/\s+/, $params, 3);
	if (not defined $to or defined $extra) {
		Irssi::print('Usage: /oconn target [source], source may be . for local server');
		return;
	}

	$to .= '.freenode.net' if $to !~ /\./;
	if ($from) {
		$from .= '.freenode.net' if $from !~ /\./;
		$from = $server->{real_address} if $from eq '.';
		# if connect fails the first time we can try again with the short form
		$split_from{$to} = $from;
	} else {
		$from = $split_from{$to};
	}

	$server->send_raw("CONNECT $to 8004 $from");
}

sub no_sconnect {
	my ($a, $b, $c) = split(/\s+/, $_[0], 3);
	Irssi::print("USE: /oconn $a $c");
}

# /rehash all *
