#!/usr/bin/perl
use warnings;
use strict;
no strict 'refs';

eval "use POSIX; POSIX::nice(10);";

use Socket;

my $mangling = '028';
if (scalar(@ARGV) > 3 or (scalar(@ARGV) > 2 and not $ARGV[2] =~ m/^[01]$/)) {
	$mangling = shift;
}
my $username = shift;
my $password = shift;
my $filter = shift;

$0 = "Armagetron Ratings";
$0 .= ": $username" if $username;
my $iaddr = inet_aton('stats.aa.dashjr.org');
my $paddr = sockaddr_in(9999, $iaddr);

my ($si, $nc) = (5, 0);
my %buf;
my ($rb, $wR, $wE);
my ($lastconnect, $lastfail) = (0, 0);

sub doConnect() {

while (1) {
	$si = 5 if $nc < time() and $lastconnect > $lastfail;
	sleep($nc - time()) if $nc > time();
	$nc = time() + $si;
	$si = $si * 2;
	$si = 300 if $si > 300;
	$lastfail = time();
	
	socket(SOCK, PF_INET, SOCK_STREAM, 0) || do {
		warn "socket: $!";
		next;
	};
	connect(SOCK, $paddr) || do {
		warn "connect: $!";
		next;
	};
	select SOCK;
	$| = 1;
	
	print SOCK "name_mangling $mangling\n";
	if (<SOCK> ne "OK $mangling\n") {
		warn "Failed to negotiate name mangling";
		next;
	}
	
	last unless $username;
	
	use Digest::MD5 qw(md5_hex);
	print SOCK "get_salt\n";
	my $salt = <SOCK>;
	if (not defined $salt) {
		warn "Lost connection during authentication (get_salt)";
		next;
	};
	chomp $salt;
	my $token = md5_hex("$username$salt" . md5_hex($password));
	print SOCK "auth_system $username $token\n";
	last if <SOCK> eq "$username\n";
	warn "authentication failed";
}

$lastconnect = time();
print SOCK $buf{STDIN} if defined $buf{STDIN};
$buf{STDIN} = '';
$buf{SOCK}  = '' unless defined $buf{SOCK};

$rb = '';
vec($rb, fileno(STDIN), 1) = 1;
vec($rb, fileno(SOCK ), 1) = 1;

warn "connected successfully";

}

doConnect;

while(select($wR = $rb, undef, undef, undef)) {
	for my $fh ('SOCK', 'STDIN') {
		my $other = ($fh eq 'SOCK') ? 'STDOUT' : 'SOCK';
		if (vec($wR, fileno($fh), 1)) {
			# Ready to read!
			my $srd = sysread($fh, $buf{$fh}, 1024, length($buf{$fh}));
			if ((not defined $srd) or $srd == 0) {
				# EOF
				exit if $fh eq 'STDIN';
				warn "lost connection-- attempting reconnect";
				doConnect;
				last;
			}
			if ($filter and $fh eq 'STDIN') {
				$buf{$fh} =~ s/(.*\n)//s or next;
				my $o = $1;
				while ($o =~ m/\G(?:.*?\n)*?\[L[^\]]*\]\s*(.*?\n)/mg) {
					print $other $1;
				}
			}
			else {
			print $other $buf{$fh};
			$buf{$fh} = '';
			}
		}
	}
}

