#!/usr/bin/perl -w
# Simple Perl/Tk utility to work with multiple rdesktop servers
# by Stephen Milton
#
# Config file is .rdpconsole in home directory.
# Config file commands are as follows:
#
# geometry=
# server=
# options=
# rdesktop_path=
# vncviewer_path=
#
# Where geometry is specified as x-width by y-width: default 800x600;
# server= can appear multiple times, once per server pre-set in the 
# server list.  rdesktop_path= and vncviewer_path= are optional.  
# Everything else is ignored.
#
# Now works with VNC as well as rdesktop clients.  Right-Double-click 
# to open a host using VNC, Left-Double-Click to open with rdesktop.
#
# Source code formatting and tips lifted from:
#    Alan Ford <alan at whirlnet dot demon dot co dot uk>
#    and his nifty program ptknslookup found at
#    http://www.whirlnet.demon.co.uk/linux/ptknslookup.html
#
# Color scheme of Black and Tan in honor of a fine beer combo!
#
# Modification history:
# 11/2001 - v0.25: Initial release
# 03/2002 - v0.50: Added support for vncviewer sessions, and fixed display bug
#           in server list.  (both ideas from Eric Johanson)
#
# Distributed with no warranty under the GNU Public License

require 5.003;
use English;
use Tk;
use Tk::DialogBox;
use Socket;
use VNC::DES;

sub rdp_connect;
sub vnc_connect;
sub doubleclick;
sub doubleclick2;
sub insert_server;

$VERSION = "0.50";

# Make sure to specify where your install of rdesktop and vnc are located
$RDESKTOP = "/usr/X11R6/bin/rdesktop";
$VNCVIEWER = "/usr/bin/vncviewer";

my @servers = [];
my $geometry = "800x600";
my $servercount = 0;

#
# Check cmd args
#

if (@ARGV) {
    if ($ARGV[0] eq "--help") {
	print "Usage: Use the source Luke.\n";
	exit -1;
    }
    if ($ARGV[0] eq "-h") {
	print  "Use of -h has been deprecated.  Use --help.\n";
	exit -1;
    }
}

#
# Read config file
#
my $configfile = $ENV{'HOME'}."/.rdpconsole";
if(-e $configfile) {
    open(CONFIG, "<$configfile") || die "Problem reading config: $!";
    while(<CONFIG>) {
	if (/^#/) {
	} elsif(/^server=(.*)$/i) {
	    $servers[$servercount++] = $1;
	} elsif(/^geometry=(.*)$/i) {
	    $geometry = $1;
	} elsif(/^rdesktop_path=(.*)$/i) {
	    if (-x $1) {
		$RDESKTOP = $1;
	    } else {
		die "Invalid path to rdesktop.";
	    }
	} elsif(/^vncviewer_path=(.*)$/i) {
	    if (-x $1) {
		$VNCVIEWER = $1;
	    } else {
		die "Invalid path to vncviewer.";
	    }
	}
    }
    close(CONFIG);
}

# 
# Initialize Main Window
#

my $MW = MainWindow->new(-fg => 'black', -bg => 'tan');

$MW->title("rdesktop Console");
$MW->Label(-text => "Version $VERSION - Written by\nStephen Milton<steve\@milton.com>", 
	   -fg => 'black',
	   -bg => 'tan')->pack(-side => 'bottom');
$MW->Label(-text => "Geometry = $geometry; Servers = $servercount", 
	   -fg => 'black',
	   -bg => 'tan')->pack(-side => 'bottom');

my $exit = $MW->Button(-text => 'Exit',
		       -fg => 'black',
		       -bg => 'tan', 
                       -command => sub
		       {
			   exit;
		       });
$exit->pack(-side => 'bottom', -expand => '1', -fill => 'both');

my $button2 = $MW->Button(-text => 'Add to list...',
			 -fg => 'black',
			 -bg => 'tan', 
                          -command => sub
			  {
			      insert_server;
			  });
$button2->pack(-side => 'bottom', -expand => '1', -fill => 'both');

my $button3 = $MW->Button(-text => 'Connect VNC (dbl-right)...',
			 -fg => 'black',
			 -bg => 'tan', 
                          -command => sub
			  {
			      vnc_connect;
			  });
$button3->pack(-side => 'bottom', -expand => '1', -fill => 'both');

my $button = $MW->Button(-text => 'Connect RDP (dbl-left)...',
			 -fg => 'black',
			 -bg => 'tan', 
                          -command => sub
			  {
			      rdp_connect;
			  });
$button->pack(-side => 'bottom', -expand => '1', -fill => 'both');

my $list_frame = $MW->Frame(-fg => 'black',
		            -bg => 'tan')->pack(-expand => '1', -fill => 'both', -side => 'bottom');

$MW->Label(-text => "Servers:",	
	   -fg => 'black', 
	   -bg => 'tan')->pack(-side => 'top', -anchor => 'nw');
$list_frame->Label(-text => "Connect:", 
		   -fg => 'black',
		   -bg => 'tan')->pack(-side => 'left');
my $entry_value = $list_frame->Entry(-width => '25', -relief => 'sunken')->pack(-side => 'right');

my $scroll = $MW->Scrollbar(-bg => 'tan');
$scroll->pack(-side => 'right', -fill => 'y');
my $list = $MW->Listbox(
    -yscrollcommand => ['set', $scroll],
    -relief => 'sunken',
    -width => 20,
    -height => ($servercount > 20 ? 20 : $servercount ? $servercount : 5),
    -foreground => 'tan', 
    -background => 'black',
    -highlightbackground => 'blue',
    -setgrid => 'yes',
);
$list->pack(-side => 'left', -fill => 'both', -expand => 'yes');
$scroll->configure(-command => ['yview', $list]);
$MW->minsize(1, 1);

$list->bind('all', '<Control-c>' => \&exit);
$list->bind('<Double-Button-1>' => sub {
    my($listbox) = @ARG;
    foreach (split ' ', $listbox->get('active')) {
        doubleclick $::ARG;
    }
});
$list->bind('<Double-Button-3>' => sub {
    my($listbox) = @ARG;
    foreach (split ' ', $listbox->get('active')) {
        doubleclick2 $::ARG;
    }
});

my $server = "";
if ($servercount) {
    foreach $server (sort @servers) {
	$list->insert('end', $server);
    }
} else {
    $list->insert('end', "none");
}

#
# Initialize password dialog
#

my $PWdlg = $MW->DialogBox(-title => 'VNC Password', -fg => 'black', -bg => 'tan', -buttons => ["OK", "Cancel"]);

my $entry_value2 = $PWdlg->Entry(-show => 0, -width => '25', -relief => 'sunken')->pack(-side => 'right');

$PWdlg->Label(-text => "Password:", 
	   -fg => 'black',
	   -bg => 'tan')->pack(-side => 'top');

#
# Execute Main Looping for Tk interface
#

MainLoop;

sub rdp_connect {
    my $host = $entry_value->get;
    system("$RDESKTOP -g $geometry $host &");
}

sub vnc_connect {
    my $host = $entry_value->get;
    $entry_value2->delete(0, length($entry_value2->get));
    $PWdlg->Show;
    if (length($entry_value2->get)) {
	&setvncpasswd($entry_value2->get);
	system("$VNCVIEWER -passwd /tmp/~rdptmp $host &");
    } else {
	system("$VNCVIEWER $host &");
    }
}

sub insert_server {
    my $host = $entry_value->get;
    open(CONFIG2, ">>$configfile") || die "Error: $!";
    print CONFIG2 "\nserver=".$host."\n";
    close(CONFIG2);
    $list->insert('end', $host);
}

sub doubleclick {
    my($host) = @ARG;
    system("$RDESKTOP -g $geometry $host &");
}

sub doubleclick2 {
    my($host) = @ARG;
    $entry_value2->delete(0, length($entry_value2->get));
    $PWdlg->Show;
    if (length($entry_value2->get)) {
	&setvncpasswd($entry_value2->get);
	system("$VNCVIEWER -passwd /tmp/~rdptmp $host &");
    } else {
	system("$VNCVIEWER $host &");
    }
}

sub setvncpasswd {
    my ($pw) = @ARG;

    while (length($pw) < 8) {
	$pw .= chr(0);
    }

    my @akey = (23, 82, 107, 6, 35, 78, 88, 7);
    my $key = "";
    foreach $kval (@akey) {
	$key .= chr($kval);
    }
    my $encrypted = "";
    &VNC::DES::deskey($key, 0);
    &VNC::DES::des($pw, $encrypted);
    ($encrypted) = $encrypted =~ /^(.{8,8})/;
      
    open(OUTF, ">/tmp/~rdptmp") || die "$!";
    print OUTF $encrypted;
    close(OUTF);
}
