#!/usr/bin/perl
#
# console <host>/<machine> -- interactive client interface
#
# The main interactive client interace to conmux.  Allows direct
# interaction with the payload, as well as allowing break out
# to the conmux menu to envoke defined commands; for example
# hardreset.
#
# (C) Copyright IBM Corp. 2004, 2005, 2006
# Author: Andy Whitcroft <andyw@uk.ibm.com>
#
# The Console Multiplexor is released under the GNU Public License V2
#
$| = 1;

our $P = 'console';

use FindBin;
use POSIX qw(errno_h BUFSIZ);
use IO::Socket;
use Getopt::Long qw(:config no_auto_abbrev);

my $CONMUX = $FindBin::Bin;
my $CONMUX = $ENV{'CONMUX_ROOT'} if ($ENV{'CONMUX_ROOT'});

# Find our internal libraries.
use lib $FindBin::Bin;
use Conmux;

# Basic terminal handling.
sub termRaw {
	$termSettings = `stty -g`;
	system "stty raw -echo opost onlret";
}
sub termRestore {
	system "stty $termSettings";
}

my $bot;
my $list;
my $status;
GetOptions(
        'b|bot=s'	=> \$bot,
	'l|list'	=> \$list,
	's|status'	=> \$status,
);
sub usage {
	warn "Usage: $P <service>\n";
	warn "       $P <registry>/<service>\n";
	warn "       $P <host>:<port>\n";
	warn "       $P --status <service>\n";
	die  "       $P --list [<registry>]\n";
}

my $id;
if ($bot) {
	$id = 'bot:' . $bot;
} else {
	$id = 'user:' . $ENV{'LOGNAME'};
}

#
# MODE: registry list.
#
if ($list) {
	if ($#ARGV == -1) {
		print Conmux::Registry::list('-');

	} elsif ($#ARGV == 0) {
		print Conmux::Registry::list($ARGV[0]);

	} else {
		usage();
	}
	exit 0
}

#
# COMMAND: payload status command
#
if ($status) {
	usage() if ($#ARGV != 0);

	my $sock;
	eval {
		$sock = Conmux::connect($ARGV[0]);
	};
	if ($@) {
		print "unavailable\n";
		exit 0
	}
	my %r = Conmux::sendCmd($sock, 'CONNECT', { 'id' => $id,
		'to' => 'console', 'hide' => 1 });
	if ($r{'status'} ne 'OK') {
		print "unavailable\n";

	} elsif ($r{'state'}) {
		print "$r{'state'}\n";

	} else {
		print "unknown\n";
	}
	exit 0;
}


#
# COMMAND: general payload connect.
#
if ($#ARGV != 0) {
	usage();
}

# Connect to the host/port specified on the command line,
# or localhost:23
my $sock = Conmux::connect($ARGV[0]);

my %r = Conmux::sendCmd($sock, 'CONNECT', { 'id' => $id, 'to' => 'console' });
die "$P: $ARGV[0]: connect failed - $r{'status'}\n" if ($r{'status'} ne 'OK');

print "Connected to $r{'title'} (~\$quit to exit)\n";
#display message of the day passed by the server e.g. who is already connected
print "$r{'motd'}";

my $rin = $win = $ein = '';
vec($rin, fileno(STDIN), 1) = 1;
vec($rin, fileno($sock), 1) = 1;
my $ein = $rin | $win;

# We want to buffer output to the terminal.  This prevents the program
# from blocking if the user hits CTRL-S for example.
# XXX ^^^

termRaw();

# Loop waiting for input from the user, or from the server.
while (1) {
	$nfound = select($rout=$rin, $wout=$win, $eout=$ein, undef);
	if ($nfound < 0) {
		if ($! == EINTR || $! == EAGAIN) {
			next;
		}
		die "$P: select failed - $!\n";
	}

	if (vec($rout, fileno(STDIN), 1)) {
		$len = sysread(STDIN, $data, 4096);
		if ($len <= 0) {
			if ($len < 0) {
				if ($! == EINTR || $! == EAGAIN) {
					next;
				}
				die "$P: STDIN: read failed - $!\n";
			}
			print STDERR "Connection Closed (client)\n";
			last;
		}
		print $sock $data;
	}
	if (vec($rout, fileno($sock), 1)) {
		$len = sysread($sock, $data, 4096);
		if ($len <= 0) {
			if ($len < 0) {
				if ($! == EINTR || $! == EAGAIN) {
					next;
				}
				die "$P: server: read failed - $!\n";
			}
			print STDERR "Connection Closed (server)\n";
			last;
		}
		print $data;
	}
}

termRestore();
