##
## $Id: EqlScript.pm,v 1.1.2.2 2003/05/23 17:59:47 seth Exp $
##

#######################################################################
## Copyright (c) 2002, 2003 by EqualLogic, Inc.
##
## All rights reserved.  This software may not be copied, disclosed,
## transferred, or used except in accordance with a license granted
## by EqualLogic, Inc.  This software embodies proprietary information
## and trade secrets of EqualLogic, Inc.
#######################################################################

use strict;
use Net::Telnet;

#
# Declare the package name
#
package EqlScript;


#
# Module Name:
#
#   EqlScript::new
#
# Module Description:
#
#  This method is designed to do the initial setup for all telnet objects. It will
#  make a connection to the group if the group parameter is supplied
#
# Input Parameters:
#
#   $group   - The name of the group you want to connect to
#   $timeout - The timeout for operations
#
# Output Parameters:
#
#   An instance of the object - if successful
#
# API:
#
#   $telnetSession = EqlScript->new( Group   => $group,
#                                    Timeout => $timeout );
#

sub new {
    my ($class, %args ) = @_;
    my ($self, $host, $timeout);

    $self->{telnet} = Net::Telnet->new( Errmode => 'return',
					Prompt  => '/^\S+>\s*$/m' );
#
# parse the positional arguments
#

    foreach( keys %args )
    {
	if (/^-?group$/i)
	{
	    $host = $args{$_};
	}
	elsif (/^-?timeout$/i)
	{
	    $self->{telnet}->timeout($args{$_});
	}
	else {
	    $self->{telnet}->error('usage: '. ref($self) . '->new(' .
				   '[Group => $host,] ' .
				   '[Timeout => $secs,])');
	    return;
	}
    }

#
# if a hostname was supplied, attempt to open a connection to it
#

    if (defined $host)
    {
	$self->{telnet}->open($host) or return;
    }

#
# everything went well so return the newly created object
#

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





#
# Module Name:
#
#   EqlScript::open
#
# Module Description:
#
#  This method is designed to log into a PeerStorage group and extract the CLI prompt.
#
# Input Parameters:
#
#   $group    - The group name
#
# Output Parameters:
#
#   1 - if successful
#   0 - if not successful
#
# API:
#
#   $result = open( $group );
#   $result = open( Group  => $group,
#                   Timeout  => $timeout );
#

sub open {
    my ($self) = @_;
    my (
	$host,
	$timeout,
	%args,
	$usage,
	);
    local $_;

    $usage = 'usage: '. ref($self) . '->open(' . '[Group => $host,] ' .
	'[Timeout => $secs,])';

    if (@_ == 2) {  # just username and passwd given
	$host = $_[1];
    }
    else
    {
	## Get the named args.
	(undef, %args) = @_;
	## Parse the named args.
	foreach (keys %args)
	{
	    if (/^-?group$/i)
	    {
		$host = $args{$_};
		defined($host)
		    or $host = "";
	    }
	    elsif (/^-?timeout$/i)
	    {
		$timeout = $self->{telnet}->timeout($args{$_});
	    }
	    else {
		return $self->{telnet}->error($usage);
	    }
	}
    }

#
# Make sure the hostname is defined
#

    if ( !$host )
    {
	return $self->{telnet}->error($usage);
    }

#
# Establish the connection to $host
#

    return $self->{telnet}->open($host);
}





#
# Module Name:
#
#   EqlScript::login
#
# Module Description:
#
#  This method is designed to log into a PeerStorage group and extract the CLI prompt.
#
# Input Parameters:
#
#   $account  - The login account (cannot be root)
#   $password - The login password
#
# Output Parameters:
#
#   1 - if successful
#   0 - if not successful
#
# API:
#
#   $result = login( $account, $password );
#   $result = login( Account  => $account,
#                    Password => $password,
#                    Timeout  => $timeout );
#

sub login {
    my ($self) = @_;
    my (
	$username,
	$passwd,
	$timeout,
	%args,
	$usage,
	);
    local $_;

    $usage = 'usage: '. ref($self) . '->login(' . '[Account => $account,] ' .
	'[Password => $password,] ' . '[Timeout => $secs,])';

    if (@_ == 3) {  # just username and passwd given
	$username = $_[1];
	$passwd = $_[2];
    }
    else
    {
	## Get the named args.
	(undef, %args) = @_;
	## Parse the named args.
	foreach (keys %args)
	{
	    if (/^-?account$/i)
	    {
		$username = $args{$_};
		defined($username)
		    or $username = "";
	    }
	    elsif (/^-?pass/i)
	    {
		$passwd = $args{$_};
		defined($passwd)
		    or $passwd = "";
	    }
	    elsif (/^-?timeout$/i)
	    {
		$timeout = $self->{telnet}->timeout($args{$_});
	    }
	    else {
		return $self->{telnet}->error($usage);
	    }
	}
    }

#
# make sure both a username and a password were supplied
#

    if ( !$username or !$passwd )
    {
	return $self->{telnet}->error($usage);
    }

#
# login to the PeerStorage group CLI
#    
    $self->{telnet}->login( Name     => $username,
			    Password => $passwd,
			    Timeout  => 10 ) or return 0;

##    printf("telnet->login succeeded\n");

#
# hack to wait for eqllog logged-in message
#
    my ( $line );
    while ( 1 )
    {
	$line = $self->{telnet}->getline(Timeout => 3);
	if ( $self->{telnet}->timed_out or $line =~ /netmgtd/ )
	{
	    last;
	}
    }

#
# set the CLI format to be parsing friendly
#

#
# do not return a failure of "cli-settings events off" fails because
# it is not supported in all releases
#

##    printf("cli-settings events off\n");
##    $self->{telnet}->cmd( "cli-settings events off" );

#
# do not return a failure of "cli-settings formatoutput off" fails because
# it is not supported in all releases
#

##    printf("cli-settings formatoutput off\n");
##    $self->{telnet}->cmd( "cli-settings formatoutput off" );

#
# fail if either of these commands fail
#
    $self->{telnet}->cmd( "cli-settings paging off" ) or return 0;
    $self->{telnet}->cmd( "cli-settings confirmation off" ) or return 0;

#
# get the prompt
#
    $self->{prompt} = $self->get_prompt;

    return 1;
}





#
# Module Name:
#
#   EqlScript::cmd
#
# Module Description:
#
#  This method executes a CLI command
#
# Input Parameters:
#
#   $command    - command to execute
#
# Output Parameters:
#
#   $result - output
#
# API:
#
#   $result = cmd( $command );
#

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

    my @result;
    my $line;
    my $add_command = 0;

    $self->{error} = undef;
    $self->{errmsg} = undef;

    @result = $self->{telnet}->cmd( $command );
    foreach $line ( @result )
    {
	if ( $line =~ /^\s*\^\s*$/ )
	{
	    $add_command = 1;
	    next;
	}

	if ( $line =~ /^\s*(%\s+)?Error[:]?\s+.*$/ )
	{
	    $self->{error} = 1;
	    $self->{errmsg} = $self->{prompt} . " ". $command . "\n" if $add_command;
	    $self->{errmsg} .= join("", @result);
	    return;
	}
    }

    wantarray ? @result : 1;
}




#
# Module Name:
#
#   EqlScript::err
#
# Module Description:
#
#  This method indicates an error occurred
#
# Input Parameters:
#
# Output Parameters:
#
#   1 - if last command failed
#
# API:
#
#   $result = err();
#

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

    return $self->{error};
}




#
# Module Name:
#
#   EqlScript::errmsg
#
# Module Description:
#
#  This method indicates an error occurred
#
# Input Parameters:
#
# Output Parameters:
#
#   last error message
#
# API:
#
#   $result = errmsg();
#

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

    return $self->{errmsg};
}





#
# Module Name:
#
#   EqlScript::timeout
#
# Module Description:
#
#  This method sets the default command timeout
#
# Input Parameters:
#
#   $to    - timeout in seconds
#
# Output Parameters:
#
#   1 - if successful
#
# API:
#
#   $result = timeout( $to );
#

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

    return $self->{telnet}->timeout( $to);
}





#
# Module Name:
#
#   EqlScript::get_prompt
#
# Module Description:
#
#  This internal method is designed to dynamically determine the CLI
#  prompt after a login
#
# Input Parameters:
#
# Output Parameters:
#
#   prompt - if successful
#
# API:
#
#   $result = get_prompt();
#

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

    my ($line, $prompt);

    $self->{telnet}->print("");
    ($line, $prompt) = $self->{telnet}->waitfor(Match   => '/^\S+>/m',
						Timeout => 1);

    return $prompt;
}




#
# Module Name:
#
#   EqlScript::get_prompt
#
# Module Description:
#
#  This internal method is designed to dynamically determine the CLI
#  prompt after a login
#
# Input Parameters:
#
# Output Parameters:
#
#   prompt - if successful
#
# API:
#
#   $result = get_prompt();
#

sub get_prompt_bad {
    my ($self) = @_;
    my (
	$data,
	$iters,
	);

    if ( 0 )
    {
    $self->{telnet}->print("");

    $iters = 0;

    while ( $iters < 5 )
    {
	$data = $self->{telnet}->getline( Timeout => 1 );

	$data =~ /^(\w+>)\s*$/m;
	if ( $1 )
	{
#            $self->{telnet}->buffer_empty;
	    return $1;
	}

	$iters++;
	$self->{telnet}->print("");
    }
    }

    my @lines = $self->{telnet}->cmd(" ");
    print "lines: ", @lines;

    if ( $lines[$#lines] =~ /^([\w\d]+>)\s*$/ )
    {
	return $1;
    }

    return;
}



sub prompt_processing_crap()
{
    my ( $prompt1,
	 $prompt2,
	 $self,
	 );
#
# figure out the prompt
#

if ( 0 )
{
    $prompt1 = $self->get_prompt();
    if ( !$prompt1 )
    {
	return 0;
    }

    $prompt2 = $self->get_prompt();
    if ( !$prompt2 or ($prompt1 ne $prompt2) )
    {
	return 0;
    }

#
# set the command prompt
#

    my $prompt = "\/^$prompt1" . "\\s\*\$\/m";
    printf("the prompt is $prompt\n");

#    $self->{telnet}->prompt( $prompt );
}
#     $self->{telnet}->prompt( '/^[\w\d]+>\s*$/m' );


    my @lines;
if ( 0 ) {
    while ( 1 )
    {
	@lines = $self->{telnet}->getlines( Timeout => 1 );
	if ($self->{telnet}->timed_out)
	{
	    last;
	}
	printf("flushing: @lines\n");
    }
}

if ( 0 )
{
    $self->{telnet}->print("member show");
    while ( 1 )
    {
	@lines = $self->{telnet}->getlines( Timeout => 1 );
	if ($self->{telnet}->timed_out)
	{
	    last;
	}
	printf("mem show res: @lines\n");
    }

    my ($prematch, $match);

    $self->{telnet}->buffer_empty;
    $self->{telnet}->print("member show");
    ($prematch, $match) = $self->{telnet}->waitfor( Match => "/psg5>/", Timeout => 1 );
    printf("mem show 2 res: '$prematch' '$match'\n");

}
#    $self->{telnet}->prompt("/psg5>/");

}

1;

__END__;

