#!/usr/bin/perl
# Mandriva Remote FrameBuffer 
#
# Copyright (C) 2001, 2002, 2003 Mandriva Daouda Lo (daouda at mandriva dot com)
#
# 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, 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 lib qw(/usr/lib/libDrakX/);
use standalone;
use keyboard;
use strict;
use common;
BEGIN { unshift @::textdomains, 'rfbdrake' }
use ugtk2 qw(:all);
use mygtk2 qw(gtknew);
use Expect;

# For Debugging
#$Expect::Log_Stdout=1;
#$Expect::Debug=3;
#$Expect::Exp_Internal=1;

my $version = "1.4";
my $copyright = "2001-2007";
#my $pix_dir = "/usr/share/rfbdrake/pixmaps";
my ($win_global, $runvnc);

my $confdir = "$ENV{HOME}/.rfbdrake";
my $rdesktopcf = $confdir . "/" . "rdesktoph";
my $vnccf = $confdir . "/" . "vnch";

#compatibility
mkdir_p($confdir) if !-d $confdir;
foreach my $files (["$ENV{HOME}/.rfb_hist", $vnccf], ["$ENV{HOME}/.rfb_hist_win", $rdesktopcf]) {
    -e $files->[0] and system("mv", $files->[0], $files->[1]);
}

set_steps();

sub get_keymaps() {
    my @keymp;
    my $path2keymaps = "/usr/share/rdesktop/keymaps/";
    my $DIR;
    opendir $DIR, $path2keymaps or die N("Opendir error: %s", $!);
    @keymp = grep { !/common/ && !/modifiers/ && -f "$path2keymaps/$_" } readdir($DIR);
    closedir $DIR;
    my $kb = keyboard::read(); 
    my $keyboard = member($kb->{KEYBOARD}, @keymp) ? $kb->{KEYBOARD} : 'en-us';
    my ($kb_used, $keyboards) = partition { $_ eq $keyboard } @keymp; 
    unshift(@$keyboards, $kb_used->[0]);
    @$keyboards;
}

sub set_steps() {
    $win_global = ugtk2->new(N("Rfbdrake %s", $version), center => 1);
    gtkset_size_request($win_global->{window}, 540, 430) if !$::isEmbedded;
    $win_global->{rwindow}->set_position('center') if !$::isEmbedded;
    my $nb_global = Gtk2::Notebook->new; my $nb = Gtk2::Notebook->new; 
    foreach my $tab ($nb_global, $nb) { $tab->set_show_tabs(0); $tab->set_show_border(0) }
    my $client_rad = Gtk2::RadioButton->new_with_label(undef, N("Want to take control (linux client)"));
    my $server_rad = Gtk2::RadioButton->new_with_label_from_widget($client_rad, N("Allow control of my machine (linux server)"));
    my $win_rad = Gtk2::RadioButton->new_with_label_from_widget($client_rad, N("Windows Terminal Services"));
    my $button_cancel = Gtk2::Button->new(" " . N("Cancel") . " ");
    $button_cancel->signal_connect(clicked => \&quit_global);
    my $button_connect = Gtk2::Button->new(" " . N("Connect") . " ");
    my $button_help = Gtk2::Button->new(" " . N("Help") . " ");
    my $hbox_final = Gtk2::HBox->new(0, 1);
    $hbox_final->pack_start($button_help, 0, 0, 1) if !$::isEmbedded; $hbox_final->pack_end($button_cancel, 0, 0, 1); $hbox_final->pack_end($button_connect,0, 0, 1);
    gtkappend_page($nb,
		   gtkpack_(Gtk2::VBox->new(0, 2),
			    if_(!$::isEmbedded, 0, Gtk2::Banner->new('/usr/share/icons/large/rfbdrake.png', N("Remote Access Configuration"))),
			    0, gtknew('Title2', label => N("Remote Access Type")),
                      0, gtksignal_connect($client_rad, clicked => sub { $nb_global->set_current_page(0); $button_connect->child->set(N("Connect")) }),
                      0, gtksignal_connect($server_rad, clicked => sub { $nb_global->set_current_page(1); $button_connect->child->set(N("Launch server")) }),
                      0, gtksignal_connect($win_rad, clicked => sub { $nb_global->set_current_page(2); $button_connect->child->set(N("Connect")) }),
			    0, $nb_global,
			    1, Gtk2::Label->new(''),
			    0, gtkpack($hbox_final)
			   )
		  );
    gtkappend_page($nb,
		   gtkpack_(Gtk2::VBox->new(0, 3),
			     0, Gtk2::Banner->new('/usr/share/icons/large/rfbdrake.png', N("Help")),
			     1, create_scrolled_window(gtktext_insert(Gtk2::TextView->new, N(" Remote FrameBuffer - Copyright (C) %s Mandriva S.A.", $copyright) . "\n\t\t\t" . N("Author:") . "   Daouda Lo (daouda at mandriva dot com)\n\n\t " . N("The rfbdrake tool is both a client and server desktop remote control utility.") . "\n\t " . N("It exports the framebuffer of the X server to one or more clients using strong\n\t compression and injects keyboard and mouse inputs from the clients into\n\t the server.") . "\n\n\t" . N("Rfbdrake allows to initiate a Window Terminal Services session with a\n\t Windows 2000/XP server.") . "\n\n\t " . N("The password is encrypted and one should always set it before giving the\n\t control to a remote client.\n"))),
			     0, gtksignal_connect(Gtk2::Button->new(N("Click Here to return")), clicked => sub { $nb->prev_page }),
			   ),
		  ) if !$::isEmbedded;
    gtkadd($win_global->{window}, $nb);
    gtkappend_page($nb_global,
			  gtkpack_(Gtk2::VBox->new(0, 5),
			    0, gtknew('Title2', label => N("Client configuration")),
				   0, create_packtable({ homogeneous => 1, col_spacings => 5, row_spacings => 5 },
						       [ gtknew('Label_Left', text => N("Remote server Address")), my $host_ip = Gtk2::Combo->new ],
						       [ gtknew('Label_Left', text => N("Display Number (default = 0)")), my $display = Gtk2::Entry->new ],
						       [ gtknew('Label_Left', text => N("Enter Password")), my $pass_client = Gtk2::Entry->new ],
						       [   my $full_toggle = Gtk2::CheckButton->new(N("FullScreen")) ],
						      ),
                          1, Gtk2::VBox->new,
                   ));
    gtkappend_page($nb_global,
                          gtkpack__(Gtk2::VBox->new(0, 5),
                                  gtknew('Title2', label => N("Server configuration")),
                                  create_packtable({ homogeneous => 1, col_spacings => 5, row_spacings => 5 },
                                  [ gtkpack(gtknew('Label_Left', text => N("Set Password"))),
                                           gtkpack(my $pass_serv = Gtk2::Entry->new) ],
                                          )));
    gtkappend_page($nb_global,
                          gtkpack_(Gtk2::VBox->new(0, 5),
                                   0, gtknew('Title2', label => N("Windows Terminal Services")),
                                   0, create_packtable({ homogeneous => 1, col_spacings => 5, row_spacings => 5 },
                                                       [ gtknew('Label_Left', text => N("Windows Hostname")), my $win_serv = Gtk2::Combo->new ],
                                                       [ gtknew('Label_Left', text => N("Screen Size")), my $win_size = Gtk2::Combo->new ],
                                                       [ gtknew('Label_Left', text => N("Keyboard Language")), my $keymaps = Gtk2::Combo->new ],
#						       [ N("Colour number"), my $bitmaps = Gtk2::ComboBox->new ],
                                                       [   my $full_wts = Gtk2::CheckButton->new(N("FullScreen")) ],
                                                      )));
    my $pass_bool = 'FALSE';
    $button_help->signal_connect("clicked", sub { $nb->set_current_page(1) });
#    map { touch("$ENV{HOME}/$_") } (".rfb_hist", ".rfb_hist_win");
    my $client_list = get_host_list($vnccf);
    -f $vnccf and $host_ip->set_popdown_strings(keys %$client_list);
    $pass_client->get_chars(0, -1);
    my $server_list = get_host_list($rdesktopcf);
    -f $rdesktopcf and $win_serv->set_popdown_strings(keys %$server_list);
    $win_size->set_popdown_strings("1024x768", "1280x1024", "1600x1200", "800x600");
    $keymaps->set_popdown_strings(get_keymaps());
    set_values_changed($win_serv, $win_size, $keymaps, $server_list);
    $pass_serv->signal_connect(changed => sub { $pass_bool = 'TRUE' });
    $win_serv->entry->signal_connect(changed => sub { set_values_changed($win_serv, $win_size, $keymaps, $server_list) });
    $pass_client->set_visibility(0); 
    $pass_serv->set_visibility(0); 
    $button_connect->signal_connect("clicked", sub {   
					my $page = $nb_global->get_current_page;
					if ($page <= 0) {
					    my $disp = $display->get_chars(0, -1);
					    my $tog = $full_toggle->get_active ? '-fullscreen' : '-shared';
					    $disp = 0 if $disp eq '';
					    my $host_cl = $host_ip->entry->get_text;
					    if ($host_cl eq '') { 
						raiseerror("\n " . N("Enter a valid address please!") . "\n");
					    } else {
						my $passcli = $pass_client->get_chars(0, -1);
						refresh_cf($vnccf, $host_cl, '', '');
						$runvnc = Expect->spawn("/usr/bin/vncviewer $tog $host_cl:$disp");
						$runvnc->log_stdout($::testing);
						my $timeout;
						$runvnc->expect($timeout,
								[ qr/Password: $/, sub {
								      my $fh = shift;
								      $fh->send("$passcli\n");
								      exp_continue;
								  } ],
								[ qr/Reading password failed/, sub { raiseerror("\n" . N("Reading password failed") . "\n") } ], 
								[ qr/authentication failed/, sub { raiseerror("\n" . N("Password incorrect") . "\n") } ],
								#[ qr/authentication succeeded/, sub { my $fh = shift; $fh->interact() } ],
								[ timeout => sub { raiseerror("Cannot connect to server.\nAborting ...") } ],
								[ qr/Unable to connect to VNC server/, sub { raiseerror("\n" . N("Unable to connect to VNC server") . "\n") } ],
								[ qr/Couldn't convert '$host_cl' to host address/, sub { raiseerror("\n" . N("Couldn't convert %s to host address", $host_cl) . "\n") } ]
							       );
						$runvnc->hard_close;
					    }
					} elsif ($page == 1) {
					    if ($pass_bool eq 'TRUE') {
						my $pserv=$pass_serv->get_chars(0, -1);
						$pserv = `genpassHex '$pserv' 2>&1`;
						my $x0rfbserver_conffile = "$ENV{HOME}/.x0rfbserver";
						if (-e $x0rfbserver_conffile) {
						    substInFile { s/^Password =.*/Password = \Q$pserv/ } $x0rfbserver_conffile;
						} else {
						    output $x0rfbserver_conffile, qq([Connection]
SocketConnections = 1
Display = 0
AutoDisplay = 1
Password = $pserv
DisableRemote = 0
DisableLocal = 0

[Update]
ShowMousePointer = 1
ScanDelay = 150
UseXShm = 1
UseXTest = 1
) }
						exec("/usr/bin/x0rfbserver") if -e "/usr/bin/x0rfbserver";
						raiseerror(N("\nInstall the rfb package if you want to export \nyour desktop to a remote client\n"));
					    } else { 
						raiseerror(N("\nYou must enter a password!\n"));
					    }
					} elsif ($page == 2) {
					    my $host_win = $win_serv->entry->get_text;
					    if ($host_win eq '') {
						raiseerror("\n " . N("Enter a valid address please!") . " \n");
					    } else {
						my $tog = if_($full_wts->get_active, '-f'); 
						my $size_win = "-g " . $win_size->entry->get_text . "+0+0";
						my $keymap_choice = "-k " . $keymaps->entry->get_text;
						refresh_cf($rdesktopcf, $host_win, $win_size->entry->get_text, $keymaps->entry->get_text);
						exec("rdesktop $tog $size_win $keymap_choice $host_win") if -e "/usr/bin/rdesktop";
						raiseerror(N("\nRdesktop is not installed,\ninstall it with 'urpmi rdesktop'\n"));
					    }
					}
				    });
    $win_global->{rwindow}->show_all;
    gtkflush();
    $win_global->main;
    ugtk2->exit(0);
}

sub set_values_changed {
    my ($server, $resolution, $keymaps, $serverlist) = @_;
    my $lastcon = $server->entry->get_text;
    if (exists $serverlist->{$lastcon}) {
	$serverlist->{$lastcon}{res} and $resolution->entry->set_text($serverlist->{$lastcon}{res});
	$serverlist->{$lastcon}{km} and $keymaps->entry->set_text($serverlist->{$lastcon}{km});
    }
}
sub refresh_cf {
    my ($file, $host, $res, $keymap) = @_;
    my $str = $host . ':' . $res . ':' . $keymap;
    #print " CHAIN = **$str**\n";
    substInFile { s/^$host:?.*/$str/; if (eof && ! /^\b$host\b/) { $_ .= $str . "\n" } } $file;
}
sub get_host_list {
    my ($file) = @_;
    my %listofserv;
    foreach my $l (cat_($file)) {
	chomp($l);
	my ($host, $res, $k) = $l =~ /^(.*):(.*?):(.*?)$/;
	#print "HOST = *$host*\tRES = *$res*\tKEYMAP = *$k*\n\n";
	$listofserv{$host}{res} = $res;
	$listofserv{$host}{km} = $k;
    }
    \%listofserv;
}
sub raiseerror {
    my $w = ugtk2->new(N("Error"), grab => 1, center => 1, transient => $win_global->{window}{window});
    gtkadd($w->{window},
	   gtkpack_(Gtk2::VBox->new,
		    1, Gtk2::Label->new($_[0]),
		    0, Gtk2::HSeparator->new,
		    0, gtksignal_connect(Gtk2::Button->new(N("Ok")), clicked => sub { Gtk2->main_quit })
		   ),
	  );
    $w->main;
}
sub quit_global() {
    ugtk2->exit(0);
}
