###########################################################################
#
# CopyLeft Veli Mankinen 2002
# HL-log/rcon bot irssi script.
#
#####################
#
# USAGE:
#
# 1. copy the script to ~/.irssi/scripts/
# 2. Edit the variables below.
# 3. load the script: /script load hlbot
# 4. Join to the channel you want this script to work on.
# 5. Make sure all the users have ops in the channel (security reasons)
# 6. say in channel: .rcon logadress <ip> <port>
#    Where ip is the ip of the machine where this script is running and
#    the port is the $listen_port you have set below
# 7. say in channel: .rcon log on
# 
# The script should now start flooding the channel about things hapening in
# the channel. Ofcourse you can and I think you should add those
# log -commands to your hl server.cfg.
#
# You can turn the flooding of by saying: ".log off" and turn it back on
# with: ".log off". ".status" tells you whether the log is on or off.
# Please note that the logfile is allways on. If you don't want to gather
# the log in a file then you should put "/dev/null" to the $logfile below.
# 
#
# NOTE: There probably are few stupid things in this script and that is
#       just because I don't have a clue about making irssi script.
#
##

use strict;
use Socket;
use Sys::Hostname;
use IO::Handle;

use Irssi;
use Irssi::Irc;
use vars qw($VERSION %IRSSI);

##########################[ USER VARIABLES ]########################### 

my $listen_port  = 10001;              # Port to listen to
my $logfile      = "logi";             # Logfile

my $hlserver     = "123.123.123.123";  # Ip of your half life server
my $hlport       = "28000";            # Port of your half life server
my $rcon_pass    = "password";         # Rcon password of your half life server

my $channel      = "#mychan";          # Channel where you want this to work

#######################################################################
##############[ YOU DON'T NEED TO TOUCH BELOW THIS LINE ]##############
#######################################################################

$VERSION = "1.0";
%IRSSI = (
	authors => "Veli Mankinen",
	contact => "veli\@piipiip.net",
	name => "HL-log/rcon -bot",
	description => "Floods the channel about things that are hapening in your hl -server. Also enables you to send rcon commands to the server from channel.",
	license => "GPLv2",
	url => "http://piipiip.net/",
);

#####################

my $serv_iaddr = inet_aton($hlserver)    || die "unknown host: $hlserver\n";
my $serv_paddr = sockaddr_in($hlport, $serv_iaddr); 
my $challenge = "";
my $rcon_msg = "";
my $log_on = 1;

#####################

sub run_bot {	
	my $server = Irssi::active_server();
	my $msg;
	
	(my $hispaddr = recv(S, $msg, 1000, 0)) or print "$!\n";
	my ($port, $hisiaddr) = sockaddr_in($hispaddr);
	my $host = inet_ntoa($hisiaddr); 

	$msg =~ s/\n.$//s;
	$msg =~ s/\n..$//s;
	
	print LOG "$host : $msg\n";

	# Received logline
	if ($msg =~ s/^˙˙˙˙log L \d\d\/\d\d\/\d{4} - \d\d:\d\d:\d\d: //) {
		# We don't want to see these
		if ($log_on eq 0 ||
			$msg =~ /^Server cvar/ || 
			$msg =~ /^\[META\]/ ||
			$msg =~ /^Log file/ || 
			$msg =~ /^\[ADMIN\]/) 
			{ return; }
		
		# FORMAT THE LINE
		# Don't show the rcon password.
		$msg =~ s/^(Rcon: "rcon \d* )[^ ]*( .*)/$1*****$2/;
		
		# Print the logline
		if ($msg =~ /^"/) {
			$server->command("/action $channel $msg");
		} else {
			$server->send_raw("PRIVMSG $channel :*log* $msg");
		}
	} 

	# Received challenge rcon reply..
	elsif ($msg =~ /^˙˙˙˙challenge rcon (\d+)$/ && $rcon_msg) {
		$challenge = $1;
		my $data = "˙˙˙˙rcon $challenge $rcon_pass $rcon_msg";
		defined(send(S, $data, 0, $serv_paddr)) or
			$server->command("/notice $channel Error sending rcon: $!");
	}

	# Received rcon reply
	elsif ($msg =~ s/˙˙˙˙l//) {
		# Some rcon replies have this annoying log entry in the beginning.
		$msg =~ s/L \d\d\/\d\d\/\d{4} - \d\d:\d\d:\d\d: //g;
		
		# FORMAT THE LINE
		
		# Multiline rcon responses
		if ($msg =~ /\n/s) {
			my @rows = split /\n/, $msg;
			foreach my $row (@rows) {
				# We don't want to see these
				if ($row =~ /^[\t \n]*$/ ||
					$row =~ /^[ADMIN] Load/ ||
					$row =~ /^[ADMIN] WARNING/ ||
					$row =~ /^[ADMIN] Plugins loaded/) 
					{ next; }

				$server->command("/notice $channel $row");
			}
			
		# Single line rcon responses
		} else {
			$server->command("/notice $channel $msg");
		}
	}
	
}

############################

sub msg_command {
	my ($server, $data, $nick, $mask, $target) = @_;
	
	# Is this the right channel?
	unless ($target =~ /$channel/i) { return; }
	
	# Does the user have ops?
	my $CHAN = $server->channel_find($channel);
	my $NICK = $CHAN->nick_find($nick);
	if (! $NICK->{op}) { return; }
		
	# Rcon command.
	if ($data =~ /^\.rcon (.+)/) {
		$rcon_msg = $1;
		
        defined(send(S, "˙˙˙˙challenge rcon", 0, $serv_paddr)) or
			$server->command("/notice $channel Error asking challenge: $!");
	} 

	# log on
	elsif ($data =~ /^\.log on$/) {
		$log_on = 1;
		$server->command("/notice $channel Logging now ON");
	}
	
	# log off
	elsif ($data =~ /^\.log off$/) {
		$log_on = 0;
		$server->command("/notice $channel Logging now OFF");
	}
	
	# help
	elsif ($data =~ /^\.help$/) {
		$server->command("/notice $channel Commands: .rcon <rcon command>, " .
			".log <on/off>, .status");
	}

	# status
	elsif ($data =~ /^\.status$/) {
		my $log_status = "";
		if ($log_on eq 1) { $log_status = "on"; }
		else { $log_status = "off"; }
		$server->command("/notice $channel Log: $log_status");
	}
	
}

#########[ MAIN ]###########

# Open the logfile.
open LOG, ">>", $logfile or die "Cannot open logfile!\n";
LOG->autoflush(1);

# Start listening the socket for udp messages.
my $iaddr = gethostbyname(hostname());
my $proto = getprotobyname('udp');
my $paddr = sockaddr_in($listen_port, $iaddr);
socket(S, PF_INET, SOCK_DGRAM, $proto)   || die "socket: $!\n";
bind(S, $paddr)                          || die "bind: $!\n";

# Set input and signals etc. irssi related stuff.
Irssi::input_add(fileno(S), INPUT_READ, "run_bot", "");
Irssi::signal_add_last('message public', 'msg_command');


