#!/usr/bin/perl
#
# Ideen:
# 1. node sollte sich aus ~/config/cluster heraussuchen, was fr eine
# Art von node es darstellen soll, also einen AK1A-Node, einen CLX Node
# oder eine User-Schnittstelle.
# OK - geht
#
# 2. User-Schnittstelle implementieren, es sollte reichen, da man 
# DX-Input und Output sieht.
# OK - geht
#
# 3. Kontroll-Terminal implementieren. Kommunikation ber Socket, wobei
# mit select() auf entweder Kommandos von <STDIN> oder von Socket
# gewartet wird. Einfaches Men implementieren, mit dem man verschiedene
# Arten von Meldungen erzeugen kann, z.B. eine zu forwardende Nachricht,
# DX- und Announce, Userlogin und -logout, Node Connect/Disconnect,
# User Info (Homenode, Name, QTH, Location)
# OK - geht
#
# 4. Help-Bildschirm machen, damit man sieht, wie man das Ganze in
# Betrieb nehmen muss.
# Fehlt noch

use Socket;

$mycall = 'unknown';
$prog = 'testnode';
if ($ARGV[0] ne '') { $mycall = $ARGV[0]; }
$mycall =~ tr/A-Z/a-z/;
$home = (getpwnam('clx_us'))[7];
$cfg = "$home/config/cluster";
$litmonths = "JanFebMarAprMayJunJulAugSepOctNovDec";
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime();
$year += 1900;
$today = sprintf("%2d-%3s-%4d",$mday,substr($litmonths,$mon*3,3),$year);
$now = sprintf("%02d%02dZ",$hour,$min);

$port = 41114;
$proto = getprotobyname('tcp');
socket(SERVER, PF_INET, SOCK_STREAM, $proto) ||\
	die "socket: $!\n";
setsockopt(SERVER, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)) ||\
	die "setsockopt: $!\n";

$_ = <DATA>;
chomp(@calls = split(/,/));

$_ = <DATA>;
chomp(@loggers = split(/,/));

$_ = <DATA>;
chomp(@freqs = split(/,/));

$_ = <DATA>;
chomp(@nodes = split(/,/));

$bound = 0;
while (! $bound) {
        if (bind(SERVER, sockaddr_in($port, INADDR_ANY))) {
                $bound = 1;
        } else {
                $port++;
                die "No more ports" if ($port > 41119);
        }
}

listen(SERVER,0) || die "listen: $!";

select(STDOUT);

$connected = 0;
$sockconn = 0;

while (1) {

        vec($rin,fileno(STDIN),1) = 1;
        vec($rin,fileno(SERVER),1) = 1;

	$rout = $rin;
	$nfound = select($rout, undef, undef, undef);

	if (vec($rout,fileno(SERVER),1)) {

		$paddr = accept(CLIENT,SERVER);
		my($port,$iaddr) = sockaddr_in($paddr);
		$name = gethostbyaddr($iaddr,AF_INET);
		vec($rin,fileno(CLIENT),1) = 1;
		$sockconn = 1;
		&menu;
		syswrite(CLIENT,$prompt,length($prompt),0);
	}

	if (vec($rout,fileno(CLIENT),1) && $sockconn) {
		$len = sysread(CLIENT,$_,1024);
		vec($rout,fileno(CLIENT),1) = 0;

		$_ =~ tr/\r\n//d;

		if (/1/) {
			$tel = 'PC11';
			$freq = @freqs[int(rand($#freqs))];
			$call = @calls[int(rand($#calls))];
			$date = $today;
			($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime();
			$time = sprintf("%02d%02dZ",$hour,$min);
			$cmt = '';
			$logger = @loggers[int(rand($#loggers))];
			$node = @nodes[int(rand($#nodes))];
			$hops = 'H99';

			if ( $usermode == 0 ) {

				$out = sprintf("%s^%s^%s^%s^%s^%s^%s^%s^%s^~\n",
					$tel,$freq,$call,$date,$time,
					$cmt,$logger,$node,$hops);

				print STDOUT $out;
			} else {
				$logger .= ':';
				$out = sprintf("DX de %-9s %8s  %-12s %-29s %6s\n",
					$logger,$freq,$call,$cmt,$time);

				print STDOUT $out;
			}
		}

		if (/2/) {
			$tel = 'PC16';
			$call = @loggers[int(rand($#loggers))];
			$node = @nodes[int(rand($#nodes))];
			$hops = 'H99';
			if (rand(100) > 80) { $here = 0 } else { $here = 1 }
			$user = "$call" . " - " . "$here";

			if ($usermode == 0) {
				$out = sprintf("%s^%s^%s^%s^\n",$tel,$node,$user,$hops);

				print STDOUT $out;
			}

			$tel = 'PC17';
			$out = sprintf("%s^%s^%s^%s^\n",$tel,$call,$node,$hops);
			push(@loggedin,$out)
		}
		if (/3/) {
			if ($#loggedin >= 0) {
				$out = pop(@loggedin);
				if ($usermode == 0) {
					print STDOUT $out;
				}
			} else {
				$msg = "No users logged in, please add some users first\n";
				syswrite(CLIENT,$msg,length($msg),0);
			}
		}
		if (/m/) { &menu; }
		if (/q/) {

			shutdown(CLIENT,2);
			vec($rin,fileno(CLIENT),1) = 0;
			$sockconn = 0;
			next;
		}

		syswrite(CLIENT,$prompt,length($prompt),0);
	}


	if (vec($rout,fileno(STDIN),1)) {

		$len = sysread(STDIN,$_,1024);
		tr/\r\n//d;

		if ( $connected == 0 ) {
			if (/[Cc]onn/) {
				($con,$medium,$destination) = (split / +/);
		
				$found = 0;
				open(CFG, "< $cfg") || die "Cannot open $cfg";
				while (<CFG>) {
					if (/^\-*$destination[\t\s]+/) {
						$found = 1;
						($c,$flags,$rest) = split;
						@f = split(//,$flags);
						$cmsg = 'Connect mode: ';
						if ($f[1] eq 'a') { 
							$cmsg .= 'active '; 
							$active = 1;
						}
						if ($f[1] eq 'p') { 
							$cmsg .= 'passive '; 
							$active = 0;
						}
						if ($f[2] eq '-') { 
							$cmsg .= 'AK1A '; 
							$clx = 0;
						}
						if ($f[2] eq '+') { 
							$cmsg .= 'CLX '; 
							$clx = 1;
							$usermode = 0;
						}
						if ($f[3] eq 'u') { 
							$cmsg .= 'in User Mode with link check'; 
							$usermode = 1;
						}
						elsif ($f[3] eq 'U') { 
							$cmsg .= 'in User Mode without link check'; 
							$usermode = 1;
						}
						else { 
							$cmsg .= 'in Protocol Mode.'; 
							$usermode = 0;
						}
					}
				}
				close(CFG);
				die "Callsign $destination not found in $cfg - aborting" 
					if (! $found);
				
				print "*** connected to $destination\n"; 
				$connected = 1;
				$prompt = $destination . " ->";
				open(LOG,"> /tmp/$destination.log") || die "cannot open logfile\n";
				select(LOG);
				$| = 1;
		
				select(STDOUT);
				$| = 1;
		
				$msg = sprintf("Started new log for %s session.",$destination);
				&syslog($msg);
				&syslog($cmsg);
		
				if ($usermode == 0) {
					print "PC38^\n";
					print "PC18^1 nodes, 1 local / 1 total users  Max users 724  Uptime 0 00:05^5447^\n";
				} else {
					print "Hi, this is $prog, test software for CLX\n";
					($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime();
					$time = sprintf("%02d%02dZ",$hour,$min);
					print "$mycall de $destination    $today    $time >\n";
				}
					
				$msg = sprintf("CONN request for %s received from %s.",$destination,$mycall);
				&syslog($msg);
			}
		} else {

			if (/^$/) { 
				&syslog('Empty line ignored.');
				next;
			}
		
			if ($usermode == 0) {
				if (/^PC10/) { 
					($tel,$from,$tonode,$text,$dummy,$to,$fromnode) = (split /\^/);
					$msg = sprintf("TALK %s@%s->%s@%s \"%s\"",$from,$fromnode,$to,$node,$text);
					&syslog($msg);
					next;
				}
			
				if (/^PC12/) { 
					($tel,$from,$to,$text,$dummy,$node,$flag,$hops) = (split /\^/);
					$msg = sprintf("ANN de %s@%s->%s \"%s\"",$from,$node,$to,$text);
					&syslog($msg);
					next;
				}
			
				if (/^PC11/) { 
					($tel,$freq,$call,$date,$time,$dummy,$logger,$node,$hops) = (split /\^/);
					$logger = $logger . "\@" . $node . ":";
					$msg = sprintf("DX de %-20s %-15s %10s %11s %5s",$logger,$call,$freq,$date,$time);
					&syslog($msg);
					next;
				}
			
				if (/^PC16/) { 
					($tel,$node,$user,$hops) = (split /\^/);
					($call,$conf,$here) = split(/ /,$user);
					$msg = sprintf("USER add %s at %s",$call,$node);
					&syslog($msg);
					next;
				}
			
				if (/^PC17/) { 
					($tel,$user,$node,$hops) = (split /\^/);
					$msg = sprintf("USER delete %s at %s",$user,$node);
					&syslog($msg);
					next;
				}
			
				if (/^PC18/) { 
					($tel,$dummy,$version) = (split /\^/);
					print "PC20^\n";
					&syslog('INIT received, version nr. $version');
					next;
				}
			
				if (/^PC19/) {
					(@list) = (split /\^/);
					$tel = shift(@list);
					while ($#list > 1) {
						$here = shift(@list);
						$node = shift(@list);
						$conf = shift(@list);
						$version = shift(@list);
						$msg = sprintf("NODE add %s, Version: %s",$node,$version);
						&syslog($msg);
					}
					$hops = shift(@list);
					next;
				}
			
				if (/^PC20/) { 
					($tel) = (split /\^/);
					foreach (@nodes) {
						print "PC19^0^$_^0^5447^H10^\n";
					}
					print "PC16^$mycall^DL6RAI-99 - H1^H1^\n"; 
					print "PC22^\n"; 
					$msg = sprintf("INIT Done received");
					&syslog($msg);
					next;
				}
			
				if (/^PC21/) {
					($tel,$node,$msg,$hops) = (split /\^/);
					$msg = sprintf("NODE delete %s",$node);
					&syslog($msg);
					next;
				}
			
				if (/^PC22/) {
					($tel) = (split /\^/);
					$msg = sprintf("INIT PCDone received");
					&syslog($msg);
					next;
				}
			
				if (/^PC23/) {
					($tel,$date,$hour,$sf,$a,$k,$cmt,$logger,$fromnode,$hops) = (split /\^/);
					$msg = sprintf("WWV de %s@%s: %s %sz: %s/%s/%s",$logger,$fromnode,$date,$hour,$sf,$a,$k);
					&syslog($msg);
					next;
				}
			
				if (/^PC24/) {
					($tel,$call,$here,$hops) = (split /\^/);
					$msg = sprintf("USER here status %s: %s",$call,$here);
					&syslog($msg);
					next;
				}
			
				if (/^PC28/) {
					($tel,$fromnode,$tonode,$from,$to,$date,$time,$private,$subject) = (split /\^/);
					$nr = int(rand(9999)+1);
					print "PC30^$tonode^$fromnode^$nr^\n";
					$msg = sprintf("MAIL forward initialised, my nr. %d",$nr);
					&syslog($msg);
					next;
				}
			
				if (/^PC29/) {
					($tel,$fromnode,$tonode,$nr,$text) = (split /\^/);
					$msg = sprintf("MAIL forward line: \"%s\"",$text);
					&syslog($msg);
					next;
				}
			
				if (/^PC30/) {
					($tel,$tonode,$fromnode,$nr) = (split /\^/);
					$msg = sprintf("MAIL forward %s->%s ACK-Subj nr. %d",$fromnode,$tonode,$nr);
					&syslog($msg);
					next;
				}
			
			
				if (/^PC32/) {
					($tel,$fromnode,$tonode,$nr) = (split /\^/);
					print "PC33^$tonode^$fromnode^$nr^\n";
					$msg = sprintf("MAIL forward completed, my nr. %d",$nr);
					&syslog($msg);
					next;
				}
			
				if (/^PC33/) {
					($tel,$tonode,$fromnode,$nr) = (split /\^/);
					$msg = sprintf("MAIL forward %s->%s Complete Text nr. %d",$fromnode,$tonode,$nr);
					&syslog($msg);
					next;
				}
			
				if (/^PC38/) {
					($tel,$rest) = (split /\^/);
					(@list) = (split /,/,$rest);
					while ($#list > -1) {
						$node = shift(@list);
						$msg = sprintf("NODE add %s",$node);
						&syslog($msg);
					}
					next;
				}
			
				if (/^PC40/) {
					($tel,$tonode,$fromnode,$filename,$bullflag,$linecount) = (split /\^/);
					$msg = sprintf("FILE forward %s->%s, name %s, %d lines",$fromnode,$tonode,$filename,$linecount);
					&syslog($msg);
					next;
				}
			
				if (/^PC41/) { 
					($tel,$from,$nr,$info,$hops) = (split /\^/);
					$type="Nr $nr";
					if ( $nr == 1 ) { $type = "name"; }
					if ( $nr == 2 ) { $type = "qth"; }
					if ( $nr == 3 ) { $type = "location"; }
					if ( $nr == 4 ) { $type = "homenode"; }
					$msg = sprintf("USER info %s %s: %s",$type,$from,$info);
					&syslog($msg);
					next;
				}
			
				if (/^PC44/) {
					($tel,$tonode,$fromnode,$stream,$qual,$key,$user) = (split /\^/);
					$msg = sprintf("REMDB request %s, key %s by %s",$qual,$key,$user);
					&syslog($msg);
					next;
				}
			
				if (/^PC45/) {
					($tel,$tonode,$fromnode,$stream,$info) = (split /\^/);
					$msg = sprintf("REMDB response %s",$info);
					&syslog($msg);
					next;
				}
			
				if (/^PC46/) {
					($tel,$tonode,$fromnode,$stream,$info) = (split /\^/);
					$msg = sprintf("REMDB complete");
					&syslog($msg);
					next;
				}
			
				if (/^PC47/) {
					($tel,$tonode,$fromnode,$user,$qual,$key,$stream,$type) = (split /\^/);
					$msg = sprintf("REMDB update %s, user %s, key %s",$qual,$user,$key);
					&syslog($msg);
					next;
				}
			
				if (/^PC50/) { 
					($tel,$node,$count,$hops) = (split /\^/);
					$msg = sprintf("USER count at %s: %d",$node,$count);
					&syslog($msg);
					next;
				}
			
				if (/^PC51/) { 
					($tel,$from,$to,$type) = (split /\^/);
					print "PC51^$to^$from^0^\n"; 
					&syslog('PING received and we responded');
					next;
				}

				print ">>$_:<< Command not understood.\n";
			}

			if ($usermode == 1) {
				if (/^DX de/) {
					($dummy,$dummy,$logger,$freq,$call,$rest) = split (/\s+/);
					$msg = sprintf("DX de %-20s %-15s %10s",$logger,$call,$freq);
					&syslog($msg);
					next;
				}
				print ">>$_:<< Command not understood.\n";
			}
		
		}
	}
}

close(LOG);

#
# Eintrag in System-Log
#
sub syslog {
    local($msg) = @_;
    print LOG "$msg\n";
}


sub menu {
$buf = <<EOF;;

           Node Menu for $destination

  1 - DX (PC11)
  2 - User Logon (PC16)
  3 - User Logoff (PC17)
  4 - Send a Mail Message
  m - Show Menu

  q - Quit

EOF
syswrite(CLIENT,$buf,length($buf),0);

}




__DATA__
3A/DF4MAA,3A/DJ5MN,3A2VB,3V8BB,4X6SJ,4Z5IS,5A1A,5N2SYT,5N9KWO,5X4F,5Z4BZ,7K3EOP/1,7X2DG,8P9IJ,8P9IK,9A4EW,9H4CM,9K2/KD4ZDP,9K2MU,9K5/YO9HP,9K5MR,9N1HP,9V1WW,A41KT,A41LZ,A71BY,A71EZ,A92GE,ACTIVITY,AH6NV,BV7GA,C31UA,C94AI,CN8ET/M,CN8KD,CN8NK,CT3FT,CX2CC/D2,CX4GL,CX5DY,DG9BEM,DL1IAO,DL5VJ/DU1,DL5ZM,DS5RNM,DU1/KC6KL,DU1SAN,DU2SAN,E21CJN,E3A30,EA8CN,EM1KA,F1AKK/P,FY5YE,FY5YF,GB3RAL,GD/AI5P,GJ3EML,HA7UL,HS0/IK4MRH,HS8FZ,I3LLH,IK0PHY,IK2NBV/BCN,IK6TJR,IK6ZKG,IK7XWJ,IK8IFV,IS0AGY,IS0YTA,IW6MNT,IW8CVV,IW9ELR,IZ2ACZ,J28EP,J28JJ/7O,JA8EO,JA9BGO,JA9BHJ,JE3RT,JX7DFA,JY26ZZ,JY5FA,JY6ZZ,KA3UNQ/P,LU1AO,LU2CFC,LU2DS,LU9HUP,LW4DWN,OH1SIX,ON4RIP,P29TL,P43WLP,PJ5AA,PT7WX,PU2MRY,PW8TR,RA9DX,RK9JWZ,S57TW,S59ZA,SP3IOE,SP6VXO,SP6YCG,SU2AM/1,SV0GR,SV5BYR,SV9/DJ4TR,T77CD,T91EAM,TK5BF,UA0BAK,UN/W0AIS,UN7TX,VK2TB,VK2ZC,VK3EW,VK3RP,VK8AN,VK8KTC,VP2KF,VR2KF,VR2KM,VU2CBE,VU2VKC,W5WQN,W6PM,WL7HP,WL9HP,XU1FL,YB1KGR,YB1XUR,YB4FIK,YB6MF,YC1VV,ZA5B,ZB2FX,ZD7WRG,ZL2CD,ZL4OL,ZP8YA,ZS1YC,ZS6PW
9A3PA,DB0BCC,DD0VF,DF2PY,DF3HU,DF7TU,DG9BEM,DH3YAK,DJ5DA,DJ6TK,DJ9HQ,DK0BP,DK3VN,DK4QT,DK4WD,DK6TP,DL0YE,DL1SV,DL1ZBE,DL2AMH,DL5DLX,DL8FCX,DL8USA,DL8YRM,F5AOF,F5GPE,F5NLY,F5PYI,F5PZQ,F5SIH,F5TNI,G0IVZ,G3BJD,G3RRS-9,G4RKV,G4WXT,GI0KOW,HA3MQ,HB9DLE,HB9KAR,HB9RG,I2VDX,I4MKN,I6AYS,I7SOZ,IK0IZW,IK0PHY,IK0SPY,IK1QFP,IK2ILH,IK2NBV,IK2RGT,IK2UEX,IK2WAN,IK2XZB,IK3EDJ-6,IK3TPP,IK4EFW,IK4GRO,IK4IDF,IK6BOB,IK6GZM,IK6SIO,IK6ZKG,IK7BPV,IK7LJR,IK7LMX-8,IK7MCJ-7,IK7XWJ,IK8DDN,IK8HJC-6,IK8PLK,IK8TMI,IK8WEJ,IK8YSW,IS0AGY,IT9IQQ,IT9ORA,IT9POD,IT9STG,IT9ZGY,IV3THL,IV3VBM,IW6MNT,IW9ELR,OE1XTU,OE2LCM,OE3PFW,OE5BWN,OE6GLD,OE8KFQ,ON5GK,OZ5EV,OZ7GO,PE1OGF,S53CAB,S53X,S55OO,S59ZA,SP3JHY,SP6VXO,SP6YCG,VK3EW-9
10103.0,10103.4,10103.5,10103.6,10107.0,14002.7,14003.0,14004.0,14004.3,14005.5,14006.1,14006.9,14007.0,14009.7,14009.8,14010.3,14011.5,14014.3,14014.6,14018.1,14018.3,14020.6,14023.4,14023.7,14027.3,14030.9,14034.8,14167.0,14176.0,14176.2,14180.0,14180.1,14185.5,14186.0,14189.0,14189.8,14192.9,14193.0,14193.7,14194.0,14195.0,14196.9,14197.0,14198.0,14198.1,14199.7,14199.8,14199.9,14200.0,14203.0,14205.0,14205.4,14210.0,14214.0,14214.7,14215.0,14220.0,14222.1,14226.5,14226.8,14227.0,14238.3,14240.0,14258.3,14259.8,14259.9,14260.0,14260.4,14266.8,14267.0,14307.0,144100.0,144135.0,144185.0,144280.0,144300.0,144550.0,144900.0,18076.5,18079.5,18081.0,18112.7,1840.0,21004.5,21007.0,21007.6,21009.5,21013.0,21013.5,21020.0,21020.5,21027.0,21081.6,21081.7,21085.0,21183.2,21212.0,21216.4,21225.0,21230.0,21231.8,21234.0,21243.0,21245.0,21250.0,21255.0,21255.3,21259.0,21259.8,21260.0,21260.2,21264.0,21265.0,21275.1,21279.8,21280.0,21283.0,21300.0,24930.0,28185.7,28215.0,28320.0,28350.0,28465.0,28490.0,28495.0,28550.0,3503.9,3793.0,432200.0,50025.0,50110.0,50120.0,50153.0,7002.4,7002.5,7002.7,7003.9,7004.0,7004.1,7005.1,7005.3,7007.7,7008.0,7008.1,7008.9,7009.0,7011.9,7012.0,7021.0
DB0AJA-15,DB0AMU-9,DB0EAM-4,DB0RDX,DB0SDX,DB0SPC-8,DF0KW-8,EA3BHK-5,EA3CW-5,EA5RS-5,F6KNL-3,F6KRQ-3,GB7BPQ,GB7DXC,GB7DXH,GB7LDX,GB7PDX,GB7SDX,HB9CGB-8,HB9IAC-8,HB9W-8,OE7XCT,ON4DXA,ON4DXB,ON4DXK,ON4DXL,OZ4PAC-6
__END__
