(PM) PM command-line editing & history

Todd R. Eigenschink (todd@tekinteractive.com)
Fri, 2 Jan 1998 14:43:29 -0500

While I was searching for more info about 3.8, I came across mention
of someone wanting improved command-line editing ability. That's one
of my larger peeves with ComOS. That, and "Press Return for More".

I threw something together in about half an hour yesterday on top of a
package that another guy here threw together in about half an hour.
While extremely raw, it works pretty well. I present it here for your
amusement. We're still working on it, and some other PM tools; I'm
not happy with anything I've seen so far. We'll post them when we
think they're ready for the world (probably another week or so).

This is a simple tool that's essentially a telnet filter--it uses
Term::Readline::Gnu for command-line history and editing, and
Net::Telnet to handle the Portmaster connection.

Comments and suggestions are welcome, unless you're going to comment
on how ugly the code is or how cheesy the (lack of) design is. We
know. :)

Adventurous folk can also try out the whoson() method of TEK::PM
(you'll have to call it yourself). I think that's a working version.
If not, it's close.

BTW, we're building a little integrated pm-command tool that will have
stuff like

pm whoson <host> #
pm kick <username> # find & reset the appropriate ports
pm tcpdump <username> # get IP & tcpdump for debugging
pm debug <username> # get IP, build a filter & ptrace

and assorted other goodies. We'll post it as soon as we can.

Todd

----------------------------------------------------------------------
#!/usr/bin/perl

use Term::ReadLine;

$SIG{INT} = 'IGNORE';

my $term = new Term::ReadLine 'pm';
my $host = shift;
my $pm = new TEK::PM($host);

$| = 1;

my $prompt;

$prompt = $pm->open_manual;

while (1)
{
if ($bad == 3)
{
print "You lose.\n";
$pm->close;
exit 1;
}

print $prompt;

my $login = <>;
chomp $login;

$prompt = $pm->username($login);
next if $prompt =~ /login:/;

print $prompt;
system "stty -echo";

my $password = <>;
chomp $password;
print "\n";

system "stty echo";

$prompt = $pm->password($password);

$bad++, next if $prompt =~ /login/;
last;
}

while (defined ($_ = $term->readline($prompt)))
{
print $pm->sendCommand($_);
last if $_ eq 'exit' or $_ eq 'quit';
}

print "\n" unless $_ eq 'exit' or $_ eq 'quit';

package TEK::PM;

use strict;
use Net::Telnet;

######################################################################

sub new
{
my ($class, $host, $user, $pass) = @_;

my $self = { '.conn' => undef,
'.prompt' => "",
'.host' => $host,
'.user' => $user,
'.pass' => $pass };

bless $self, $class;
return $self;
}

######################################################################

sub DESTROY
{
my ($self) = @_;
$self->close();
}

######################################################################

sub open

{
my ($self) = @_;

$self->{ '.conn' } = new Net::Telnet();

my $conn = $self->{ '.conn' };

$conn->open( $self->{ '.host'} );

$conn->waitfor( '/login: $/i' );
$conn->print( $self->{ '.user' } );

$conn->waitfor( '/Password: $/' );
$conn->print( $self->{ '.pass' } );

my $foo;
($foo, $self->{ '.prompt' }) = $conn->waitfor('/\S+>\s+/');
}

######################################################################

sub close
{
my ($self) = @_;

$self->{ '.conn' }->close() if $self->{ '.conn' };
undef $self->{ '.conn' };
}

######################################################################

sub sendCommand
{
my ($self,$command) = @_;
my $prematch = '';
my $match = '';
my $text = '';
my $prompt = $self->{ '.prompt' };
my $more = "-- Press Return for More -- ";

$self->{ '.conn' }->print( $command );

while ( 1 )
{
($prematch, $match) = $self->{ '.conn' }->waitfor( "/$more|$prompt/i");

$text .= $prematch;

if ( $match eq "-- Press Return for More -- " )
{
$self->{ '.conn' }->print("");
next;
}

last if ( $match eq $prompt or ! $match );
}

return $text;
}

######################################################################

sub whoson
{
my ($self) = @_;

my $text = '';
my $all = $self->sendCommand( "show all" );
my $ses = $self->sendCommand( "show ses" );

$text = "Ser Md Int Username Trans/Recv Connect Type " .
"Host Start Idle\n" .
"--- -- ----- -------- ----------- --------------- " .
"---------------- ------ ------\n";

my $s = $all;
while ( $s =~ /(S\d*)\s*(.{5}) (.{3}) (.{16}) /is )
{
$s = $';
my ($serial, $speed, $modem, $host) = ($1, $2, $3, $4);

$host =~ s#\s*##g;

next if ! $host;

my ($user,$ip,$start,$idle) = $ses =~
m#$serial\s*([^ ]*)\s*([^ ]*)\s*.{25}\s*([^ ]*)\s*([0-9,:]*)#;

my $connect = "$speed/$speed";
my $type = "ISDN";

if ( $modem =~ /^(M\d*)/ )
{
my $m = $self->sendCommand( "show $1" );

my ($tr,$rr,$ct) = $m =~
/Transmit Rate: (\d*).*?Receive Rate: (\d*).*?Connection Type: ([^\n]*)/si;

$connect = "$tr/$rr";
$type = $ct;
}

$modem =~ s#M##;
$modem =~ s#on##;

my $s = $self->sendCommand( "show $serial" );
$type .= "/MPP" if ( $s =~ /Multilink/ );
$type .= "/Stac" if ( $s =~ /Stac/ );

$text .= sprintf( "%-3s %-2s %-5s %-8s %-11s %-15s %-16s %6s %6s\n",
$serial, $modem, $host, $user, $connect, $type,
$ip, $start, $idle );
}

return $text;
}

######################################################################

sub kick
{
my ($self,$user) = @_;

my $ses = $self->sendCommand( "show ses" );
my $text = "Kicking User $user....\n";

while ( $ses =~ /(S\d*)\s*($user)/isg )
{
$ses = $';
$text .= " " . $self->sendCommand( "reset $1" );
}

$text .= "Done\n";

return $text;
}

######################################################################

sub prompt
{
my ($self) = @_;

return $self->{ '.prompt' };
}

######################################################################

sub open_manual
{
my ($self) = @_;

$self->{ '.conn' } = new Net::Telnet();

my $conn = $self->{ '.conn' };

$conn->open( $self->{ '.host'} );

my ($pre, $login) = $conn->waitfor( '/login: $/i' );

return $pre . $login;
}

######################################################################

sub username
{
my ($self, $username) = @_;

my $conn = $self->{ '.conn' };

$self->{ '.user' } = $username;
$conn->print( $username );

my ($pre, $pass) = $conn->waitfor( '/login: $|Password: $/' );

return $pre . $pass;
}

######################################################################

sub password
{
my ($self, $password) = @_;

my $conn = $self->{ '.conn' };

$conn->print( $password );

my $foo;
($foo, $self->{ '.prompt' }) = $conn->waitfor('/\S+>\s+|login: $/');

if ($self->{ '.prompt' } =~ /login: /)
{
return $foo . $self->{ '.prompt' };
}
else
{
return $self->{ '.prompt' };
}
}
----------------------------------------------------------------------
-
To unsubscribe, email 'majordomo@livingston.com' with
'unsubscribe portmaster-users' in the body of the message.