1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
|
#!/usr/bin/perl -w
use strict;
use IO::Socket;
use Getopt::Long;
# Created by: David Van Ginneken
# Bird's the Word Technologies
# davevg@btwtech.com
#
# And distributed under the terms of the GPL
#
my ($user, $pw, $host, $port, $interactive, $save) = (undef, undef, 'localhost', 5038, 0, 0);
my $EOL = "\r\n"; # Standard End of Line
my @commands;
process_credentials('/etc/astcli.conf');
process_credentials("$ENV{HOME}/.astcli") if defined $ENV{HOME};
GetOptions("username=s" => \$user, "secret=s" => \$pw, "host=s" => \$host, "port=s" => \$port, "readline" => \$interactive, "write" => \$save);
$|++; # Auto Flush Output
my $action = join(" ", @ARGV);
&usage if (!defined $user || !defined $pw);
my $tc = new IO::Socket::INET(
PeerAddr => $host,
PeerPort => $port,
Timeout => 30,
Proto => 'tcp'
) or die "Could not connect to Host: $host on port $port\n";
if (my $error = login()) {
print STDERR $error;
exit 1;
};
if ($save) {
if (-d $ENV{HOME}) {
open DEFAULT, ">$ENV{HOME}/.astcli";
print DEFAULT "username=$user\n" if $user;
print DEFAULT "password=$pw\n" if $pw;
print DEFAULT "hostname=$host\n" if $host;
print DEFAULT "portno=$port\n" if $port;
close DEFAULT;
}
}
# Send a single command to the manager connection handle (global $tc).
# Assumes things always work well :-)
sub send_command($) {
my $command = shift;
$tc->send('Action: Command' . $EOL);
$tc->send("Command: $command" . $EOL);
$tc->send($EOL);
my $response = '';
while (<$tc>) {
if ($_ =~ /--END COMMAND--/) {
$_ =~ s/--END COMMAND--\s*//;
$response .= $_;
last;
}
$response .= $_;
}
$response =~ s/Privilege: Command$EOL//;
$response =~ s/Response: Follows$EOL//;
return $response;
}
sub login {
my ($response, $message);
$tc->send("Action: Login" . $EOL);
$tc->send("Username: $user" . $EOL);
$tc->send("Secret: $pw" . $EOL);
$tc->send("Events: off" . $EOL);
$tc->send($EOL);
while (<$tc>) {
last if $_ eq $EOL;
$_ =~ s/$EOL//g;
($response) = $_ =~ /^Response: (.*?)$/ if $_ =~ /^Response:/;
($message) = $_ =~ /^Message: (.*?)$/ if $_ =~ /^Message:/;
}
return 0 if $response eq 'Success';
return $message;
}
sub logoff {
my ($response, $message);
$tc->send("Action: Logoff" . $EOL . $EOL);
return 1;
}
# If the user asked to send commands from standard input:
if ($action eq '-' || !defined $action || $action eq '') {
if ($interactive) {
eval { require Term::ReadLine;};
$interactive = scalar($@) ? 0 : 1;
print STDERR "Falling back to standard mode, Unable to load Term::Readline for readline mode\n" unless $interactive;
}
if ($interactive) {
my $term = new Term::ReadLine 'Command Line Interface';
my $prompt = "$host*CLI> ";
my $attribs = $term->Attribs;
$attribs->{completion_function} = \&tab_completion;
while (defined($_ = $term->readline($prompt))) {
(logoff() and exit) if $_ =~ /exit|quit/; # Give them a way to exit the "terminal"
print send_command($_) if $_ !~ m/^\s*$/;
}
} else {
while (<>) {
chomp;
(logoff() and exit) if $_ =~ /exit|quit/; # If someone accidentally ends up here, let them exit
print send_command($_);
}
}
exit 0;
}
# Otherwise just send the command:
print send_command($action);
# parses a configuration file into the global $user and $pw.
sub process_credentials {
# Process the credentials found..
my $file = shift;
# silently fail if we can't read the file:
return unless (-r $file);
open (my $fh, "<$file") or return;
while (<$fh>) {
chomp;
(undef,$user) = split(/[,=]/, $_) if $_ =~ /user(name)?[,=]/i;
(undef,$pw) = split(/[,=]/, $_) if $_ =~ /(secret|passw(or)?d|pwd?)[,=]/i;
(undef,$host) = split(/[,=]/, $_) if $_ =~ /host(name)?[,=]/i;
(undef,$port) = split(/[,=]/, $_) if $_ =~ /port(num|no)?[,=]/i;
}
close ($fh);
}
sub usage {
print STDERR "astcli [<options>] [<cli-command>|-]\n";
print STDERR " -u <name> - Connect as username <name>\n";
print STDERR " -s <pw> - Connect with secret <pw>\n";
print STDERR " -h <host> - Connect to host <host> [localhost]\n";
print STDERR " -p <port> - Connect on TCP port <port> [5038]\n";
print STDERR " -r - Start a readline session for interactivity\n";
print STDERR " -w - Save connection options in a configuration file\n";
print STDERR " You may specify the command as '-' to take commands from stdin.\n";
exit;
}
sub tab_completion {
my ($word, $buffer, $offset) = @_;
my %items;
my $lastword = '';
if ($word eq '') {
$buffer =~ m/(\S+)\s?$/;
$lastword = $1;
#print STDERR "\n\nlastword=\"$lastword\"\n";
}
my $res = send_command("_command matchesarray \"$buffer\" \"$word\"");
foreach my $item (split /\s+/, $res) {
$items{$item}++ unless ($item eq '_EOF_' or $item eq '' or $item eq $lastword);
}
#print STDERR "\nword=\"$word\" buffer=\"$buffer\" offset=\"$offset\" res=\"$res\"\n";
return sort keys %items;
}
|