Add in macro_user_1 .. 4

Add in user macros that can run an external command to pass into each
client terminal session.  Ensure that if no user command is defined that
the expected 'Alt-1' to 'Alt-4' keys are passed into the terminals
instead.

Include docs and examples of how they might be used.
This commit is contained in:
Duncan Ferguson 2019-03-28 22:52:03 +00:00
parent 900d0fabb6
commit dab4fa2237
7 changed files with 222 additions and 2 deletions

View file

@ -4,6 +4,7 @@ Revision history for {{$dist->name}}
- Include README within the repository, not just created tar.gz files
- Add 'autoquit' setting to 'File' menu (Github issue #114)
- Correct macro_hostname to be the FQDN of the server where cssh is being run (Github issue #116)
- Add in user defined macros
4.13.2_02 2019-01-14 Duncan Ferguson <duncan_ferguson@user.sf.net>
- Fix Getopt-Long minimum version

49
README
View file

@ -83,8 +83,8 @@ OPTIONS
Number of seconds to wait before closing finished terminal windows.
--autoquit, -q
Toggle automatically quitting after the last client window has closed
(overriding the config file).
Toggle automatically quitting after the last client window has
closed (overriding the config file).
--cluster-file '<filename>', -c '<filename>'
Use supplied file as additional cluster file (see also "FILES").
@ -223,6 +223,13 @@ KEY SHORTCUTS
Alt-u
Paste in the username for the connection
Alt-1
Alt-2
Alt-3
Alt-4
Run the matching user defined macro on the server and send the
output to the client
EXAMPLES
Open up a session to 3 servers
$ cssh server1 server2 server3
@ -418,14 +425,52 @@ FILES
Default key sequence to send username to client. See "KEY
SHORTCUTS" for more information.
key_user_1 = Alt-1
key_user_2 = Alt-2
key_user_3 = Alt-3
key_user_4 = Alt-4
Default key sequence to send user defined macros to client. If
the matching macro_user_1 macro is undefined, the sequence is
passed straight to the terminal. See "KEY SHORTCUTS" for more
information.
macro_servername = %s
macro_hostname = %h
macro_username = %u
macro_newline = %n
macro_version = %v
macro_user_1 = %1
macro_user_2 = %2
macro_user_3 = %3
macro_user_4 = %4
Change the replacement macro used when either using a 'Send'
menu item, or when pasting text into the main console.
macro_user_1_command =
macro_user_2_command =
macro_user_3_command =
macro_user_4_command =
User defined macros - the macro is run through the shell on the
server and the output is sent to the client. For example,
"macro_user_1_command=echo echo macro_user_1"
would send the text C<echo macro_user_1> into the terminal session.
"macro_user_1_command=env | grep CSSH"
would send the CSSH environment variables to the client.
The following environment variables are set in the shell of the
macro process
"CSSH_SERVERNAME"
"CSSH_HOSTNAME"
"CSSH_USERNAME"
"CSSH_CONNECTION_STRING"
"CSSH_CONNECTION_PORT"
"CSSH_VERSION"
macros_enabled = yes
Enable or disable macro replacement. Note: this affects all the
"macro_*" variables above.

View file

@ -49,6 +49,10 @@ my %default_config = (
key_macros_enable => "Alt-p",
key_paste => "Control-v",
key_username => "Alt-u",
key_user_1 => "Alt-1",
key_user_2 => "Alt-2",
key_user_3 => "Alt-3",
key_user_4 => "Alt-4",
mouse_paste => "Button-2",
auto_quit => "yes",
auto_close => 5,
@ -103,6 +107,15 @@ my %default_config = (
macro_username => '%u',
macro_newline => '%n',
macro_version => '%v',
macro_user_1 => '%1',
macro_user_2 => '%2',
macro_user_3 => '%3',
macro_user_4 => '%4',
macro_user_1_command => '',
macro_user_2_command => '',
macro_user_3_command => '',
macro_user_4_command => '',
max_addhost_menu_cluster_items => 6,
menu_send_autotearoff => 0,
@ -279,6 +292,15 @@ sub parse_config_file {
if ( $read_config{terminal_font} );
$self->validate_args(%read_config);
# Look at the user macros and if not set remove the hotkey for them
for my $i (qw/ 1 2 3 4 /) {
if ( ! $self->{"macro_user_${i}_command"} ) {
delete $self->{"key_user_${i}"};
}
}
return $self;
}
sub load_configs {

View file

@ -559,6 +559,12 @@ would replace the <Alt-n> with the client's name in each window.}
output $self->loc(q{Retile all the client windows.});
output '=item ', $self->parent->config->{key_username};
output $self->loc(q{Paste in the username for the connection});
output '=item ', $self->parent->config->{key_user_1} || 'Alt-1';
output '=item ', $self->parent->config->{key_user_2} || 'Alt-2';
output '=item ', $self->parent->config->{key_user_3} || 'Alt-3';
output '=item ', $self->parent->config->{key_user_4} || 'Alt-4';
output $self->loc(q{Run the matching user defined macro on the server and send the output to the client});
output '=back';
output '=head1 ' . $self->loc('EXAMPLES');
@ -768,15 +774,61 @@ If the external command is given a C<-L> option it should output a list of tags
'L<KEY SHORTCUTS>'
);
output '=item key_user_1 = Alt-1';
output '=item key_user_2 = Alt-2';
output '=item key_user_3 = Alt-3';
output '=item key_user_4 = Alt-4';
output $self->loc(
q{Default key sequence to send user defined macros to client. If the matching [_2] macro is undefined, the sequence is passed straight to the terminal. See [_1] for more information.},
'L<KEY SHORTCUTS>', 'L<macro_user_1>'
);
output '=item macro_servername = %s';
output '=item macro_hostname = %h';
output '=item macro_username = %u';
output '=item macro_newline = %n';
output '=item macro_version = %v';
output '=item macro_user_1 = %1';
output '=item macro_user_2 = %2';
output '=item macro_user_3 = %3';
output '=item macro_user_4 = %4';
output $self->loc(
q{Change the replacement macro used when either using a 'Send' menu item, or when pasting text into the main console.}
);
output '=item macro_user_1_command =';
output '=item macro_user_2_command =';
output '=item macro_user_3_command =';
output '=item macro_user_4_command =';
output $self->loc(
q{User defined macros - the macro is run through the shell on the server and the output is sent to the client. For example,},
);
output "C<macro_user_1_command=echo echo macro_user_1>";
output $self->loc(
q{
would send the text [_1] into the terminal session.
},
'C<echo macro_user_1>'
);
output "C<macro_user_1_command=env | grep CSSH>";
output $self->loc(
q{
would send the CSSH environment variables to the client.
},
);
output $self->loc("The following environment variables are set in the shell of the macro process");
output '=over';
output '=item C<CSSH_SERVERNAME>';
output '=item C<CSSH_HOSTNAME>';
output '=item C<CSSH_USERNAME>';
output '=item C<CSSH_CONNECTION_STRING>';
output '=item C<CSSH_CONNECTION_PORT>';
output '=item C<CSSH_VERSION>';
output '=back';
output '=item macros_enabled = yes';
output $self->loc(
q{Enable or disable macro replacement. Note: this affects all the [_1] variables above.},

View file

@ -20,6 +20,8 @@ use Tk::Xlib;
use Tk::ROText;
require Tk::Dialog;
require Tk::LabEntry;
use Symbol qw/ gensym /;
use IPC::Open3;
use X11::Protocol 0.56;
use X11::Protocol::Constants qw/ Shift Mod5 ShiftMask /;
use X11::Protocol::WM 29;
@ -593,17 +595,20 @@ sub substitute_macros {
my $macro_servername = $self->config->{macro_servername};
( my $servername = $svr ) =~ s/\s+//;
$text =~ s!$macro_servername!$servername!xsmg;
$ENV{CSSH_SERVERNAME} = $servername;
}
{
my $macro_hostname = $self->config->{macro_hostname};
my $hostname = hostfqdn();
$text =~ s!$macro_hostname!$hostname!xsmg;
$ENV{CSSH_HOSTNAME} = $hostname;
}
{
my $macro_username = $self->config->{macro_username};
my $username = $servers{$svr}{username};
$username ||= getpwuid($UID);
$text =~ s!$macro_username!$username!xsmg;
$ENV{CSSH_USERNAME} = $username;
}
{
my $macro_newline = $self->config->{macro_newline};
@ -613,6 +618,54 @@ sub substitute_macros {
my $macro_version = $self->config->{macro_version};
my $version = $self->parent->VERSION;
$text =~ s/$macro_version/$version/xsmg;
$ENV{CSSH_VERSION} = $version;
}
$ENV{CSSH_CONNECTION_STRING} = $servers{$svr}{connect_string};
$ENV{CSSH_CONNECTION_PORT} = $servers{$svr}{port};
# Set up environment variables in the macro environment
for my $i (qw/ 1 2 3 4 / ) {
my $macro_user_command = 'macro_user_'.$i.'_command';
my $macro_user = $self->config->{'macro_user_'.$i};
next unless $text =~ $macro_user;
if( ! $self->config->{ $macro_user_command } ) {
$text =~ s/$macro_user//xsmg;
next;
}
my $cmd = $self->config->{ $macro_user_command };
local $SIG{CHLD} = undef;
my $stderr_fh = gensym;
my $stdout_fh = gensym;
my $child_pid = eval { open3(undef, $stdout_fh, $stderr_fh, $cmd) };
if (my $err=$@) {
# error message is hardcoded into open3 - tidy it up a little for our users
$err=~ s/ at .*//;
$err=~ s/open3: //;
$err =~ s/( failed)/' $1/;
$err =~ s/(exec of) /$1 '/;
warn "Macro failure for '$macro_user_command': $err";
next;
}
waitpid($child_pid, 0);
my $cmd_rc = $? >> 8;
my @stdout = <$stdout_fh>;
my @stderr = <$stderr_fh>;
if ( $cmd_rc > 0 || @stderr ){
warn "Macro failure for '$macro_user_command'",$/;
warn "Exited with error output:: @stderr" if @stderr;
warn "Exited with non-zero return code: $cmd_rc", $/ if $cmd_rc;
} else {
#$self->send_text_to_all_servers( $stdout );
return join('', @stdout);
}
}
return $text;
@ -1545,6 +1598,18 @@ sub key_event {
$self->send_text_to_all_servers(
$self->config->{macro_username} )
if ( $hotkey eq "key_username" );
$self->send_text_to_all_servers(
$self->config->{macro_user_1} )
if ( $hotkey eq "key_user_1" );
$self->send_text_to_all_servers(
$self->config->{macro_user_2} )
if ( $hotkey eq "key_user_2" );
$self->send_text_to_all_servers(
$self->config->{macro_user_3} )
if ( $hotkey eq "key_user_3" );
$self->send_text_to_all_servers(
$self->config->{macro_user_4} )
if ( $hotkey eq "key_user_4" );
$self->add_host_by_name()
if ( $hotkey eq "key_addhost" );
$self->retile_hosts("force")

View file

@ -52,6 +52,10 @@ Readonly::Hash my %default_config => {
key_macros_enable => "Alt-p",
key_paste => "Control-v",
key_username => "Alt-u",
key_user_1 => "Alt-1",
key_user_2 => "Alt-2",
key_user_3 => "Alt-3",
key_user_4 => "Alt-4",
mouse_paste => "Button-2",
auto_quit => "yes",
auto_close => 5,
@ -109,6 +113,15 @@ Readonly::Hash my %default_config => {
macro_username => '%u',
macro_newline => '%n',
macro_version => '%v',
macro_user_1 => '%1',
macro_user_2 => '%2',
macro_user_3 => '%3',
macro_user_4 => '%4',
macro_user_1_command => '',
macro_user_2_command => '',
macro_user_3_command => '',
macro_user_4_command => '',
max_addhost_menu_cluster_items => 6,
menu_send_autotearoff => 0,
@ -188,6 +201,9 @@ $expected{screen_reserve_left} = 100;
$expected{screen_reserve_right} = 100;
$expected{screen_reserve_top} = 100;
$expected{screen_reserve_bottom} = 160;
# Note: the parse_config here removes the key_user_x entries
delete( $expected{"key_user_$_"} ) for (qw/ 1 2 3 4 /);
trap {
$config = $config->parse_config_file( $file, );
};
@ -328,6 +344,9 @@ open( my $csshrc, '>', $ENV{HOME} . '/.csshrc' );
print $csshrc 'auto_quit = no', $/;
close($csshrc);
$expected{auto_quit} = 'no';
# Note: the load_configs here removes the key_user_x entries
delete( $expected{"key_user_$_"} ) for (qw/ 1 2 3 4 /);
$config = App::ClusterSSH::Config->new();
trap {
$config->load_configs();
@ -565,11 +584,23 @@ key_macros_enable=Alt-p
key_paste=Control-v
key_quit=Alt-q
key_retilehosts=Alt-r
key_user_1=Alt-1
key_user_2=Alt-2
key_user_3=Alt-3
key_user_4=Alt-4
key_username=Alt-u
lang=en
macro_hostname=%h
macro_newline=%n
macro_servername=%s
macro_user_1=%1
macro_user_1_command=
macro_user_2=%2
macro_user_2_command=
macro_user_3=%3
macro_user_3_command=
macro_user_4=%4
macro_user_4_command=
macro_username=%u
macro_version=%v
macros_enabled=yes

View file

@ -16,6 +16,10 @@ key_paste=Control-v
key_quit=Control-q
key_retilehosts=Alt-r
key_username=Alt-n
key_user_1=Alt-1
key_user_2=Alt-2
key_user_3=Alt-3
key_user_4=Alt-4
max_host_menu_items=30
method=ssh
mouse_paste=Button-2