#!/usr/bin/perl
# Mandrake Remote FrameBuffer 
#
# Copyright (C) 2001, 2002, 2003 MandrakeSoft Daouda Lo (daouda at mandrakesoft 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 Expect;

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

my $_version = "1.0";
my $_copyright = "2001, 2002, 2003, 2004";
my $pix_dir = "/usr/share/rfbdrake/pixmaps";
my ($win_global, $runvnc);

set_steps();

sub get_keymaps {
    my @keymp;
    my $path2keymaps = "/usr/share/rdesktop/keymaps/";
    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")." ".$_version, center => 1);
    gtkset_size_request($win_global->{window}, 540, 430);
    $win_global->{rwindow}->set_position('center');
    my $nb_global = Gtk2::Notebook->new; my $nb = Gtk2::Notebook->new; 
    map { $_->set_show_tabs(0); $_->set_show_border(0) } ($nb_global, $nb);
    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("Connection")." ");
    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); $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),
			    0, set_darea(N("Remote Access Configuration"), "$pix_dir/remote.png"),
			    0, gtkadd(my $frame_sel = Gtk2::Frame->new(N("Remote Access Type")),
				      gtkpack(Gtk2::VBox->new(0, 0),
					      gtksignal_connect($client_rad, clicked => sub { $nb_global->set_current_page(0); $button_connect->child->set(N("Connection")) }),
					      gtksignal_connect($server_rad, clicked => sub { $nb_global->set_current_page(1); $button_connect->child->set(N("Launch server")) }),
					      gtksignal_connect($win_rad, clicked => sub { $nb_global->set_current_page(2); $button_connect->child->set(N("Connection")) }),
					     ),
				     ),
			    1, $nb_global,
			    0, gtkpack($hbox_final)
			   )
		  );
    gtkappend_page($nb,
		   gtkpack_( Gtk2::VBox->new(0, 3),
			     0, set_darea(N("Help"), "$pix_dir/remote.png"),
			     1, create_scrolled_window(gtktext_insert(my $text = Gtk2::TextView->new, N(" Remote FrameBuffer - Copyright (C) %s MandrakeSoft S.A.", $_copyright)."\n\t\t\t".N("Author:")."   Daouda Lo (daouda at mandrakesoft 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(my $buttonok = Gtk2::Button->new(N("Click Here to return")), clicked => sub { $nb->prev_page() }),
			   ),
		  );
    gtkadd($win_global->{window}, $nb);
    gtkappend_page($nb_global,
		   gtkadd(Gtk2::Frame->new(N("Client configuration")),
			  gtkpack_(Gtk2::VBox->new(1, 0),
				   1, create_packtable({ homogeneous => 1, col_spacings => 20, row_spacings => 20 },
						       [ N("Remote server Address"), my $host_ip = Gtk2::Combo->new() ],
						       [ N("Display Number (default = 0)"), my $display = Gtk2::Entry->new() ],
						       [ N("Enter Password"), my $pass_client = Gtk2::Entry->new() ],
						       [   "" , my $full_toggle = Gtk2::CheckButton->new(N("FullScreen")) ],
						      ))));
    gtkappend_page($nb_global,
                   gtkadd(Gtk2::Frame->new(N("Server configuration")),
                          gtkpack(Gtk2::VBox->new(1, 0),
                                  gtkpack_(Gtk2::HBox->new(1, 5),
                                           0, gtkpack(Gtk2::Label->new(N("Set Password"))),
                                           0, gtkpack(my $pass_serv = Gtk2::Entry->new),
                                          ))));
    gtkappend_page($nb_global,
                   gtkadd(Gtk2::Frame->new(N("Windows Terminal Services")),
                          gtkpack_(Gtk2::VBox->new(1, 0),
                                   1, create_packtable({ homogeneous => 1, col_spacings => 20, row_spacings => 20 },
                                                       [ N("Windows Hostname"), my $win_serv = Gtk2::Combo->new() ],
                                                       [ N("Screen Size"), my $win_size = Gtk2::Combo->new() ],
                                                       [ N("Keyboard Language"), my $keymaps = Gtk2::Combo->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");
    -f "$ENV{HOME}/.rfb_hist" and $host_ip->set_popdown_strings(load_text("$ENV{HOME}/.rfb_hist"));
    $pass_client->get_chars(0, -1);
    -f "$ENV{HOME}/.rfb_hist_win" and $win_serv->set_popdown_strings(load_text("$ENV{HOME}/.rfb_hist_win")); $win_serv->set_use_arrows_always('TRUE');
    $win_size->set_popdown_strings("1024x768", "1280x1024", "1600x1200", "800x600");
    $keymaps->set_popdown_strings(get_keymaps());
    $pass_serv->signal_connect("changed", sub { $pass_bool = 'TRUE' });
    $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();
					    unless ($host_cl ne '') { raiseerror("\n ".N("Enter a valid address please!")." \n") }
					    else {
						my $passcli = $pass_client->get_chars(0, -1);
						refresh_host_list($host_cl, "$ENV{HOME}/.rfb_hist");
						if ($passcli eq '') { 
						    foreach my $vncbin ('/usr/X11R6/bin/vncviewer', '/usr/bin/vncviewer') {
							exec("$vncbin $tog $host_cl:$disp") if -e $vncbin;
						    }
						    raiseerror(N("\nYou should install vnc client \nto connect to the server\n"));
						} else {
						    $runvnc = Expect->spawn("/usr/X11R6/bin/vncviewer $tog $host_cl:$disp");
						    $runvnc->log_stdout($::testing);
						    my $timeout = undef;
						    $runvnc->expect($timeout,
								    [ qr/Password: $/, sub {
									  my $fh = shift;
									  $fh->send("$passcli\n");
									  exp_continue;
								      } ],
								    [ 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 ...") } ],
								   );
						    $runvnc->hard_close();
						}
					    }
					} elsif ($page == 1) {
					    if (!-e "$ENV{HOME}/.x0rfbserver" || $pass_bool eq 'TRUE') {
						my $pserv=$pass_serv->get_chars(0, -1);
						$pserv = `genpassHex '$pserv' 2>&1`;
						output "$ENV{HOME}/.x0rfbserver",
						qq([Connection]
SocketConnections = 1
Display = 0
AutoDisplay = 1
Password = $pserv
DisableRemote = 0
DisableLocal = 0

[Update]
ShowMousePointer = 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"));
					} elsif ($page == 2) {
					    my $host_win = $win_serv->entry->get_text();
					    unless ($host_win ne '') { raiseerror("\n ".N("Enter a valid address please!")." \n") }
					    else {
						my $tog = if_($full_wts->get_active(), '-f'); 
						refresh_host_list($host_win, "$ENV{HOME}/.rfb_hist_win");
						my $size_win = "-g ".$win_size->entry->get_text()."+0+0";
						my $keymap_choice = "-k ".$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;
    Gtk2->main;
    ugtk2->exit(0);
}
sub set_darea {
    my ($label, $pix) = @_;
    my $darea = gtkset_size_request(Gtk2::DrawingArea->new, -1, 100);
    $darea->modify_font(Gtk2::Pango::FontDescription->from_string('Sans 14'));
    my $layout = $darea->create_pango_layout($label);
    my $pixbuf_banner = gtkcreate_pixbuf($pix);
    $darea->signal_connect(expose_event => sub {
			       fill_tiled($darea,$pixbuf_banner);
			       $darea->window->draw_layout($darea->style->fg_gc('normal'), (580-($layout->get_pixel_size)[0])/2, 35, $layout);
			       0;
			   });
    $darea; 
}
sub load_text {
    my ($file)=@_;
    my @list_hosts;
    open(FILE, $file) or die "load_text: missing file $file : $!";
    while (<FILE>) {
	chomp;
	unshift(@list_hosts, $_);
    }
    close(FILE);
    @list_hosts;
}
sub refresh_host_list {
  my ($hostname, $file) = @_;
  my @old_hosts = load_text($file);
  my $i = 0;
  open( FILE, "+>$file") or die "refresh_host_list : missing file $file : $!";
  foreach my $line (@old_hosts) {
      unless ($i == 4) {
	  next if $line eq $hostname;
	  print FILE "$line$/";
	  $i++;
      }
  }
  print FILE "$hostname$/";
  close(FILE);
}
sub raiseerror {
    my $w = ugtk2->new(N("Error"), grab => 1, center => 1, transient => $win_global->{rwindow});
    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);
}


