#!/usr/bin/perl -w
# Do a dynamic DNS client thingy.
# $Id$
use strict;
# From the perlipc manpage
use Socket;
use FileHandle;

sub dial {
	my ($socket, $remote, $port) = @_;
	my ($iaddr, $paddr, $proto, $line);

	if ($port =~ /\D/) { $port = getservbyname($port, 'tcp') }
	die "No port" unless $port;
	$iaddr   = inet_aton($remote)               || die "no host: $remote" ;
	$paddr   = sockaddr_in($port, $iaddr);

	$proto   = getprotobyname('tcp');
	socket($socket, PF_INET, SOCK_STREAM, $proto)  || die "socket: $!";
	connect($socket, $paddr)    || die "connect: $!";
}

sub authorize {
	my ($pass) = @_;
	print SERVER ">$pass\n";
	print SERVER "End of authorization information\n";
	my $authresponse = <SERVER>;
	if ($authresponse !~ /OK/) {
		die "authorization: Server says $authresponse\n";
	}
}

# Read a mapping of names to values from a file
# Stolen from the server code
sub readmapfile {
        my @xxx;
        my ($filename) = @_;
        my @rv = ();
        open MAP, $filename or die "can't open $filename: $!";
        local $_;
        while (<MAP>) {
                s/#.*//;
                next if /^\s*$/;

                @xxx = split;
                if (@xxx == 2) {
                        push @rv, $xxx[0] => $xxx[1];
                } elsif (@xxx == 0) {
                        next;
                } else {
                        warn "Can't understand $_\n";
                }
        }
        close MAP;
        return @rv;
}

sub usage {
	print <<end_of_message;
Usage: $0 passfile server hostname username command
passfile contains user-password pairs.
server is the dynamic-DNS update server.
hostname is the name of the host whose info we're trying to update.
username is the name of the person who has authority to do that.
command is the command to send to the server; it can currently be one of 
	"A xx.xxx.xx.xx", which sets the address;
	"CNAME xx.xxx.xx.xxx", which sets the host to be an alias for another;
	"CLEAR", which clears all info associated with the host.
end_of_message
	exit 5;
}

usage unless @ARGV == 5;

my ($passwords, $server, $host, $name, $cmd) = @ARGV;
my %passwords = readmapfile $passwords;

if (not exists $passwords{$name}) {
	warn "No password for $name\n";
	exit 3;
}

dial \*SERVER, $server, 5353;
autoflush SERVER 1;

my $server_version = <SERVER>;
if ($server_version =~ /^Kragen Toy-3 dynamic DNS server\r?\n/) {
	print SERVER "Kragen Toy-3 dynamic DNS client\n";
} else {
	print SERVER "You are the wrong version of server\n";
	print "Server reports $server_version -- bastard\n";
	exit 1;
}

my $response = <SERVER>;
if ($response !~ /OK/) {
	print "Server doesn't like me -- $response\n";
	close SERVER;
	exit 2;
}


print SERVER "$host\n$name\n";



# NOTE: passwords do NOT depend on server, only on username.
# This is because I was cutting a corner!
my $pass = $passwords{$name};
authorize($pass);

print SERVER $cmd, "\n";
my $response = <SERVER>;
print $response;
my $exitcode;
if ($response =~ /^OK/i) {
	$exitcode = 0;
} elsif ($response =~ /^bad/i) {
	$exitcode = 1;
} else {
	warn "not sure whether response is good or bad!\n";
	$exitcode = 2;
}

close SERVER;

exit $exitcode;
