dotfiles/bin/sshc
2017-02-15 12:23:57 -05:00

423 lines
11 KiB
Perl
Executable File

#!/usr/bin/env perl
use strict;
use warnings;
use diagnostics -verbose;
use Term::Title 'set_titlebar', 'set_tab_title';
# perltidy --backup-and-modify-in-place -l=120 -cti=2 --opening-brace-on-new-line --opening-sub-brace-on-new-line -lp -vt=0 -vtc=0 -cab=0 sshc.pl
BEGIN
{
$diagnostics::DEBUG = 0;
$diagnostics::PRETTY = 1;
if (0)
{
use Perl::Critic;
my $file = $0;
my $critic = Perl::Critic->new( -severity => '3',
-verbose => 11 );
my @violations = $critic->critique($file);
my ( $i, $n ) = ( 0, scalar @violations );
for ( reverse Perl::Critic::Violation::sort_by_severity(@violations) )
{
print '-' x 20, "\n";
printf( "%3d/%d ", ++$i, $n );
print "[" . $_->severity() . "] " . $_;
print " -- source --- \n";
print " source: ", $_->source(), "\n";
print " -- /source --- \n";
print " expl: ", $_->explanation(), "\n";
print " desc: ", $_->description(), "\n";
print " dia : ", $_->diagnostics(), "\n";
print "\n --- press Enter to continue ---\n";
<STDIN>;
}
exit;
}
}
use XML::Dumper;
use Data::Dumper;
use autodie qw< :io >;
use English qw(-no_match_vars);
$OUTPUT_AUTOFLUSH = 1;
use Curses;
use Curses::UI;
use Term::ANSIColor;
my $cui = Curses::UI->new( -color_support => 1,
-clear_on_exit => 0 );
my $ssh_config = &read_ssh_config;
#-color_support,-clear_on_exit,-mouse_support
#);
my $w = $cui->width();
my $h = $cui->height();
sub exit_dialog
{
my $return = $cui->dialog(
-message => 'Do you really want to quit?',
-title => 'Are you sure???',
-buttons => [ 'yes', 'no' ],
-border => 1,
);
exit 0 if $return;
return;
}
my %options = (
-title => 'profile',
-width => $w / 3,
-height => $h,
-border => 1,
-padtop => 3,
);
my %options_info = (
-title => 'infos',
-width => $w,
-height => 3,
-border => 1,
);
my %options2 = (
-title => 'details',
-width => $w,
-height => $options{-height},
-border => 1,
-padleft => $w - $options{-width} * 2,
-padtop => $options{-padtop},
);
my $win = $cui->add( 'window_id', 'Window', %options );
my $win_info = $cui->add( 'window_info', 'Window', %options_info );
$cui->set_binding( sub { \&exit_dialog(); }, 'q' );
my $label = $win_info->add(
'mylabel', 'Label',
-text => 'quit: q connect: ENTER',
-bold => 0,
)->draw();
#~ my $label2 = $win_info->add(
#~ 'mylabel1', 'Label',
#~ -text => 'Hello, world!\nds',
#~ -bold => 0,
#~ -x => 30
#~ )->draw();
my @values = sort { lc $a cmp lc $b } ( keys %{$ssh_config} );
my $listbox = $win->add(
'mylistbox', 'Listbox',
-values => \@values,
#~ -labels => {'12designer-dev'=>'12'},
-onselchange => sub { \&display_ssh_config($ssh_config); }
);
$listbox->set_binding( sub { &ssh_connect( $ssh_config, $listbox ) }, KEY_ENTER );
$listbox->{-onselchange}->();
$listbox->focus();
sub ssh_connect
{
my ( $config, $listbox ) = @_;
my $key = $listbox->get_active_value();
set_tab_title($key);
$cui->leave_curses();
my $cmdline = "ssh $key";
print colored ( "executing ssh : $cmdline", 'bold on_white' ), "\n";
my $e = system($cmdline);
$e /= 256;
if ( $e == 255 )
{
#~ print colored ("exit code = $e",'bold red'),"\n";
print colored ( "--- error occurred - see message above --- ", 'bold red on_black' ), "\n";
print colored ( "- press ENTER to continue ---", 'green on_white' );
<STDIN>;
}
}
# debugging function
sub dump
{
use XML::Dumper;
my $dump = new XML::Dumper;
# ===== Dump to a file
my $file = "dump.xml";
$dump->pl2xml( $_[0], $file );
}
$cui->mainloop();
sub CURSE_setProperty
{
my ( $obj, $property, $value ) = @_;
if ($obj)
{
#~ if ( exists($ob->{$property}) )
{
$obj->{$property} = $value;
$obj->draw();
}
#~ else
#~ {
#~ $cui->error(" \$obj has not such property : $property ");
#~ }
}
else
{
$cui->error('no such obj');
}
return;
}
sub display_ssh_config
{
my $config = shift;
my $key = $win->getobj('mylistbox')->get_active_value();
if ( $cui->getobj('w2') )
{
$cui->delete('w2');
}
my $win2 = $cui->add( 'w2', 'Window', %options2 )->draw();
my $offSet = {
x => 0,
y => 0
};
# $key - of the hash with the dataset
# $offset - remember the postions of the labels
# $value_key - the config-key
# $default_value- if the config-key not exists display this instead [optional]
my $subFillLabels = sub {
my ( $key_, $_offSet, $list_already_onscreen, $value_key, $default_value ) = @_;
$value_key = lc $value_key;
$list_already_onscreen->{$value_key} = 1;
my ( $label_key, $label_val ) = ( 'label_k_' . $value_key, 'label_v_' . $value_key );
my $x_offset = 20;
my $entry = $config->{$key_};
if ( exists $entry->{$value_key} || $default_value )
{
my $init_obj = sub {
my ( $_key, $options ) = @_;
if ( !$win2->getobj($_key) )
{
$win2->add( @{$options} )->draw();
}
};
$init_obj->(
$label_key,
[
$label_key, 'Label',
-text => $value_key,
-bold => 1,
-x => $_offSet->{x},
-y => $_offSet->{y}
]
);
my $value = exists $entry->{$value_key} ? $entry->{$value_key} : $default_value;
my @value_labels = ( ref $value eq 'ARRAY' ) ? @{$value} : ($value);
for my $i ( 0 .. scalar @value_labels - 1 )
{
my $_label = $label_val . '_' . $i;
$init_obj->(
$label,
[
$_label, 'Label',
-bold => 0,
-x => $x_offset,
-y => $_offSet->{y},
-text => $value_labels[$i]
]
);
$_offSet->{y} += $win2->getobj($_label)->{-height};
}
}
};
my $list_already_onscreen = { 'host' => 1 };
$subFillLabels->( ( $key, $offSet, $list_already_onscreen ), ( 'Hostname', $key ) );
$subFillLabels->( ( $key, $offSet, $list_already_onscreen ), ('User') );
$subFillLabels->( ( $key, $offSet, $list_already_onscreen ), ('Port') );
$subFillLabels->( ( $key, $offSet, $list_already_onscreen ), ('IdentityFile') );
$subFillLabels->( ( $key, $offSet, $list_already_onscreen ), ('Compression') );
$subFillLabels->( ( $key, $offSet, $list_already_onscreen ), ('LocalForward') );
$subFillLabels->( ( $key, $offSet, $list_already_onscreen ), ('RemoteForward') );
#~ $cui->leave_curses();
grep {
if ( !( exists $list_already_onscreen->{$_} ) )
{
$subFillLabels->( ( $key, $offSet, $list_already_onscreen ), ($_) );
}
} sort keys %{ $config->{$key} };
#~ <STDIN>;
return;
}
sub read_ssh_config
{
my $user = $ENV{'USER'};
my %config = ();
# temporary
my $host;
my $process_ssh_config = sub {
my ( $fh, $config ) = @_;
while (<$fh>)
{
( local $_ = $_ ) =~ s/\n//smx;
if (
m{
^(Host) # a comment
[\ \t] # or
([^#]+) # empty line
}smxi
)
{
$host = $2;
$config->{$host} = { lc "$1" => $host };
#print $host,"\n";
}
else
{
if (
m{
^\# # a comment
| # or
^$ # empty line
}smx
)
{
# ignore
}
else
{
if (
m{
([^\ \t]+) # match everything except
[\ \t] # with space and tab in between
([^\#]+) # match everthing except beginning comment
}smx
)
{
# coz the keys are case-insensitive - lower them all
my ( $key, $value ) = ( lc $1, $2 );
if ( exists $config->{$host}->{$key} )
{
if ( ref $config->{$host}->{$key} eq 'ARRAY' )
{
push @{ $config->{$host}->{$key} }, $value;
}
else
{
my $old_val = $config->{$host}->{$key};
$config->{$host}->{$key} = [ $old_val, $value ];
}
}
else
{
$config->{$host}->{$key} = $value;
}
}
else
{
warn "regex not matched \n";
}
}
}
#print $_ if (/^$/);
}
};
my $ssh_config_file = '/Users/' . $user . '/.ssh/config';
if ( -e $ssh_config_file )
{
my $error_on_open = open my $fh, q{<}, $ssh_config_file;
if ( !$error_on_open )
{
die $EXTENDED_OS_ERROR;
}
else
{
$process_ssh_config->( $fh, \%config );
my $error_on_close = close $fh;
if ( !$error_on_close )
{
die $EXTENDED_OS_ERROR;
}
}
}
else
{
$cui->error(
-message => 'please create a ssh config file : '.$ssh_config_file,
-title => 'config missing',
-buttons => [ 'ok' ],
-border => 1,
);
exit 1;
}
#~ &dump( \%config );
#~ exit;
#~ &ssh_get_connection_info( \%config, 'zeus.fh-brandenburg.de' );
#~ exit;
return \%config;
}