#! /usr/bin/perl -wT

# parseconfig.pl - parse TunnelDigger config file into per-link fragments
#                  and create dependencies
#
#    Copyright (C) 2003 Kai Henningsen <kai@debian.org>
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

use strict;
use Data::Dumper; $Data::Dumper::Useqq = 1;

%ENV = ();
$ENV{PATH} = "/usr/local/bin:/usr/bin:/bin";

die "usage: $0 configfile workingdir" unless @ARGV == 2;

my $cf = shift;
my $work = shift;

$cf =~ m/(.*)/;
$cf = $1;
$work =~ m/(.*)/;
$work = $1;

mkdir $work;
chdir $work or die "chdir $work: $!";

open CF, '<', $cf or die "$cf: $!";

my %dependencies;

while (<CF>) {
	tr/ \t\r\n//d;
	s/#.*//;
	next unless /./;
	my @f = split /;/, $_;
	die "need 13 fields: " . join(' ', @f) unless @f == 14;
	my %ep1 = &ep('S', @f[0 ... 6], $f[8]);
	my %ep2 = &ep('C', @f[7 ... 13], $f[1]);

	my $linkid = $ep1{name}.'-'.$ep2{name};
	my $linkname = $linkid.'.link';
	my $linktemp = $linkname . '.tmp';
	open LINK, '>', $linktemp or die "$linktemp: $!";
	print LINK Data::Dumper->Dump([\%ep1, \%ep2], [qw/ *ep1 *ep2 /]);
	close LINK or die "$linktemp: $!";
	&move_if_changed($linktemp, $linkname);
	$dependencies{$ep1{name}.'.'.$ep1{sys}}->{$linkid.'.conf'}++;
	$dependencies{$ep1{name}.'.'.$ep1{sys}}->{$linkid.'.conf.local'}++;

	$linkid = $ep2{name}.'-'.$ep1{name};
	$linkname = $linkid.'.link';
	$linktemp = $linkname . '.tmp';
	open LINK, '>', $linktemp or die "$linktemp: $!";
	print LINK Data::Dumper->Dump([\%ep2, \%ep1], [qw/ *ep1 *ep2 /]);
	close LINK or die "$linktemp: $!";
	&move_if_changed($linktemp, $linkname);
	$dependencies{$ep2{name}.'.'.$ep2{sys}}->{$linkid.'.conf'}++;
	$dependencies{$ep2{name}.'.'.$ep2{sys}}->{$linkid.'.conf.local'}++;
}
my $deps = 'make.deps';
open MAKE, '>', $deps or die "$deps: $!";
print MAKE "#! make\n\n";
for my $o (sort keys %dependencies) {
	print MAKE join(' ', $o, ':', sort keys %{$dependencies{$o}}), "\n";
}
print MAKE "\n";
close MAKE;

sub move_if_changed
{
	my ($tmp, $fin) = @_;
	system("cmp -s $tmp $fin || mv -v $tmp $fin");
	unlink $tmp;
}

sub ep
{
	my ($tls, $sys, $name, $eadr, $eport, $dev, $iadr, $nets, $peer) = @_;
	($name) = ($name =~ /^(\w+)$/);
	$dependencies{'_OUTPUTS_'}->{$name.'.'.$sys}++;
	$dependencies{$name.'.'.$sys}->{'$(HK)/'.$name.'.key'}++;
	$dependencies{$name.'.'.$sys}->{'$(HK)/'.$name.'.crt'}++;
	$dependencies{$name.'.'.$sys}->{'$(CA)/$(CANAME).crt'}++;
	$dependencies{$name.'.'.$sys}->{'$(CANAME).global'}++;
	my @iadr = split /,/, $iadr;
	my @nets = split /,/, $nets;
	if ($eport =~ m[^alloc/(\w+)$]) {	#]
		my $aname = $name . '-' . $1 . '.alloc';
		my ($first, $last, %alloc, %reverse) = (5000, 5999);
		sub firsttag() { '[first]' }
		sub lasttag() { '[last]' }
		if (open ALLOC, '<', $aname) {
			local $/ = undef;
			my $alloc = <ALLOC>;
			close ALLOC or die "$aname: $!";
			($alloc) = ($alloc =~ /^(.*)$/s);
			my @alloc = eval $alloc;
			%alloc = @alloc;
			$first = $alloc{firsttag()};
			$last = $alloc{lasttag()};
			delete $alloc{firsttag()};
			delete $alloc{lasttag()};
			%reverse = reverse %alloc;
		}
		if (not exists $alloc{$peer} or $alloc{$peer} < $first or $alloc{$peer} > $last) {
			my $p = $first;
			$p++ while exists $reverse{$p};
			die "$aname: out of free ports" if $p > $last;
			$alloc{$peer} = $p;
			$alloc{firsttag()} = $first;
			$alloc{lasttag()} = $last;
			open ALLOC, '>', $aname or die "$aname: $!";
			print ALLOC Data::Dumper->Dump([\%alloc], [qw/ *alloc /]);
			close ALLOC or die "$aname: $!";
		}
		$eport = $alloc{$peer};
	}
	return (
		tls => $tls,
		sys => $sys,
		name => $name,
		eadr => $eadr,
		eport => $eport,
		dev => $dev,
		iadr => [ @iadr ],
		nets => [ @nets ],
	);
}

