00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include "config.h"
00034
00035 #include <cstdlib>
00036 #include <iostream>
00037 #include <fstream>
00038 #include <sstream>
00039 #include <map>
00040
00041 using std::cout ;
00042 using std::endl ;
00043 using std::cerr ;
00044 using std::ofstream ;
00045 using std::ostringstream ;
00046 using std::ios ;
00047 using std::map ;
00048
00049 #ifdef HAVE_LIBREADLINE
00050 # if defined(HAVE_READLINE_READLINE_H)
00051 # include <readline/readline.h>
00052 # elif defined(HAVE_READLINE_H)
00053 # include <readline.h>
00054 # else
00055 extern "C"
00056 {
00057 char *readline( const char * ) ;
00058 }
00059 # endif
00060 char *cmdline = NULL ;
00061 #else
00062
00063 #endif
00064
00065 #ifdef HAVE_READLINE_HISTORY
00066 # if defined(HAVE_READLINE_HISTORY_H)
00067 # include <readline/history.h>
00068 # elif defined(HAVE_HISTORY_H)
00069 # include <history.h>
00070 # else
00071 extern "C"
00072 {
00073 int add_history( const char * ) ;
00074 int write_history( const char * ) ;
00075 int read_history( const char * ) ;
00076 }
00077 # endif
00078
00079 #endif
00080
00081 #include <libxml/encoding.h>
00082
00083 #define SIZE_COMMUNICATION_BUFFER 4096*4096
00084 #include "CmdClient.h"
00085 #include "CmdTranslation.h"
00086 #include "PPTClient.h"
00087 #include "BESDebug.h"
00088 #include "BESStopWatch.h"
00089 #include "BESError.h"
00090
00091 CmdClient::~CmdClient()
00092 {
00093 if( _strmCreated && _strm )
00094 {
00095 _strm->flush() ;
00096 delete _strm ;
00097 _strm = 0 ;
00098 }
00099 else if( _strm )
00100 {
00101 _strm->flush( ) ;
00102 }
00103 if( _client )
00104 {
00105 delete _client ;
00106 _client = 0 ;
00107 }
00108 }
00109
00124 void
00125 CmdClient::startClient( const string & host, int portVal, int timeout )
00126 {
00127 _client = new PPTClient( host, portVal, timeout ) ;
00128 _client->initConnection() ;
00129 }
00130
00140 void
00141 CmdClient::startClient( const string & unixStr, int timeout )
00142 {
00143 _client = new PPTClient( unixStr, timeout ) ;
00144 _client->initConnection() ;
00145 }
00146
00155 void
00156 CmdClient::shutdownClient()
00157 {
00158 if( _client )
00159 _client->closeConnection() ;
00160 }
00161
00178 void
00179 CmdClient::setOutput( ostream * strm, bool created )
00180 {
00181 if( _strmCreated && _strm )
00182 {
00183 _strm->flush() ;
00184 delete _strm ;
00185 }
00186 else if( _strm )
00187 {
00188 _strm->flush() ;
00189 }
00190 _strm = strm ;
00191 _strmCreated = created ;
00192 }
00193
00205 bool
00206 CmdClient::executeClientCommand( const string & cmd )
00207 {
00208 bool do_exit = false ;
00209 string suppress = "suppress" ;
00210 if( cmd.compare( 0, suppress.length(), suppress ) == 0 )
00211 {
00212 setOutput( NULL, false ) ;
00213 return do_exit ;
00214 }
00215
00216 string output = "output to" ;
00217 if( cmd.compare( 0, output.length(), output ) == 0 )
00218 {
00219 string subcmd = cmd.substr( output.length() + 1 ) ;
00220 string screen = "screen" ;
00221 if( subcmd.compare( 0, screen.length(), screen ) == 0 )
00222 {
00223 setOutput( &cout, false ) ;
00224 }
00225 else
00226 {
00227
00228 string file = subcmd.substr( 0, subcmd.length() - 1 ) ;
00229 ofstream *fstrm = new ofstream( file.c_str(), ios::app ) ;
00230 if( fstrm && !(*fstrm) )
00231 {
00232 delete fstrm ;
00233 cerr << "Unable to set client output to file " << file
00234 << endl ;
00235 }
00236 else
00237 {
00238 setOutput( fstrm, true ) ;
00239 }
00240 }
00241 return do_exit ;
00242 }
00243
00244
00245 string load = "load" ;
00246 if( cmd.compare( 0, load.length(), load ) == 0 )
00247 {
00248 string file = cmd.substr( load.length() + 1,
00249 cmd.length() - load.length() - 2 ) ;
00250 ifstream fstrm( file.c_str() ) ;
00251 if( !fstrm )
00252 {
00253 cerr << "Unable to load commands from file " << file
00254 << ": file does not exist or failed to open file" << endl ;
00255 }
00256 else
00257 {
00258 do_exit = executeCommands( fstrm, 1 ) ;
00259 }
00260
00261 return do_exit ;
00262 }
00263
00264 cerr << "Improper client command " << cmd << endl ;
00265
00266 return do_exit ;
00267 }
00268
00281 bool
00282 CmdClient::executeCommand( const string &cmd, int repeat )
00283 {
00284 bool do_exit = false ;
00285 string client = "client" ;
00286 if( cmd.compare( 0, client.length(), client ) == 0 )
00287 {
00288 do_exit = executeClientCommand( cmd.substr( client.length() + 1 ) ) ;
00289 }
00290 else
00291 {
00292 if( repeat < 1 ) repeat = 1 ;
00293 for( int i = 0; i < repeat && !do_exit; i++ )
00294 {
00295 BESDEBUG( "cmdln", "cmdclient sending " << cmd << endl ) ;
00296 BESStopWatch *sw = 0 ;
00297 if( BESISDEBUG( "timing" ) )
00298 {
00299 sw = new BESStopWatch() ;
00300 sw->start() ;
00301 }
00302
00303 map<string,string> extensions ;
00304 _client->send( cmd, extensions ) ;
00305
00306 BESDEBUG( "cmdln", "cmdclient receiving " << endl ) ;
00307
00308 bool done = false ;
00309 ostringstream *show_stream = 0 ;
00310 while( !done )
00311 {
00312 if( CmdTranslation::is_show() )
00313 {
00314 if( !show_stream )
00315 {
00316 show_stream = new ostringstream ;
00317 }
00318 }
00319 if( show_stream )
00320 {
00321 done = _client->receive( extensions, show_stream ) ;
00322 }
00323 else
00324 {
00325 done = _client->receive( extensions, _strm ) ;
00326 }
00327 if( extensions["status"] == "error" )
00328 {
00329
00330
00331 _strm->flush() ;
00332
00333
00334
00335 if( _isInteractive )
00336 {
00337 CmdTranslation::set_show( true ) ;
00338 }
00339 }
00340 if( extensions["exit"] == "true" )
00341 {
00342 do_exit = true ;
00343 }
00344 }
00345 if( show_stream )
00346 {
00347 *(_strm) << show_stream->str() << endl ;
00348 delete show_stream ;
00349 show_stream = 0 ;
00350 }
00351 if( BESDebug::IsSet( "cmdln" ) )
00352 {
00353 BESDEBUG( "cmdln", "extensions:" << endl ) ;
00354 map<string,string>::const_iterator i = extensions.begin() ;
00355 map<string,string>::const_iterator e = extensions.end() ;
00356 for( ; i != e; i++ )
00357 {
00358 BESDEBUG( "cmdln", " " << (*i).first << " = "
00359 << (*i).second << endl ) ;
00360 }
00361 BESDEBUG( "cmdln", "cmdclient done receiving " << endl ) ;
00362 }
00363 if( BESISDEBUG( "timing" ) )
00364 {
00365 if( sw && sw->stop() )
00366 {
00367 BESDEBUG( "timing", "cmdclient - executed \""
00368 << cmd << "\" in " << sw->seconds()
00369 << " seconds and " << sw->microseconds()
00370 << " microseconds" << endl ) ;
00371 }
00372 else
00373 {
00374 BESDEBUG( "timing", "cmdclient - executed \"" << cmd
00375 << "\" - no timing available"
00376 << endl ) ;
00377 }
00378 }
00379
00380 _strm->flush() ;
00381 delete sw ;
00382 sw = 0 ;
00383 }
00384 }
00385 return do_exit ;
00386 }
00387
00405 bool
00406 CmdClient::executeCommands( const string &cmd_list, int repeat )
00407 {
00408 bool do_exit = false ;
00409 _isInteractive = true ;
00410 if( repeat < 1 ) repeat = 1 ;
00411
00412 CmdTranslation::set_show( false ) ;
00413 try
00414 {
00415 string doc = CmdTranslation::translate( cmd_list ) ;
00416 if( !doc.empty() )
00417 {
00418 do_exit = this->executeCommand( doc, repeat ) ;
00419 }
00420 }
00421 catch( BESError &e )
00422 {
00423 CmdTranslation::set_show( false ) ;
00424 _isInteractive = false ;
00425 throw e ;
00426 }
00427 CmdTranslation::set_show( false ) ;
00428 _isInteractive = false ;
00429 return do_exit ;
00430 }
00431
00450 bool
00451 CmdClient::executeCommands( ifstream & istrm, int repeat )
00452 {
00453 bool do_exit = false ;
00454 _isInteractive = false ;
00455 if( repeat < 1 ) repeat = 1 ;
00456 for( int i = 0; i < repeat; i++ )
00457 {
00458 istrm.clear( ) ;
00459 istrm.seekg( 0, ios::beg ) ;
00460 string cmd ;
00461 while( !istrm.eof() )
00462 {
00463 char line[4096] ;
00464 line[0] = '\0' ;
00465 istrm.getline( line, 4096, '\n' ) ;
00466 cmd += line ;
00467 }
00468 do_exit = this->executeCommand( cmd, 1 ) ;
00469 }
00470 return do_exit ;
00471 }
00472
00492 bool
00493 CmdClient::interact()
00494 {
00495 bool do_exit = false ;
00496 _isInteractive = true ;
00497
00498 cout << endl << endl
00499 << "Type 'exit' to exit the command line client and 'help' or '?' "
00500 << "to display the help screen" << endl << endl ;
00501
00502 bool done = false ;
00503 while( !done && !do_exit )
00504 {
00505 string message = "" ;
00506 size_t len = this->readLine( message ) ;
00507 if( len == -1 || message == "exit" || message == "exit;" )
00508 {
00509 done = true ;
00510 }
00511 else if( message == "help" || message == "help;" || message == "?" )
00512 {
00513 this->displayHelp() ;
00514 }
00515 else if( message.length() > 6 && message.substr( 0, 6 ) == "client" )
00516 {
00517 do_exit = this->executeCommand( message, 1 ) ;
00518 }
00519 else if( len != 0 && message != "" )
00520 {
00521 CmdTranslation::set_show( false ) ;
00522 try
00523 {
00524 string doc = CmdTranslation::translate( message ) ;
00525 if( !doc.empty() )
00526 {
00527 do_exit = this->executeCommand( doc, 1 ) ;
00528 }
00529 }
00530 catch( BESError &e )
00531 {
00532 CmdTranslation::set_show( false ) ;
00533 _isInteractive = false ;
00534 throw e ;
00535 }
00536 CmdTranslation::set_show( false ) ;
00537 }
00538 }
00539 _isInteractive = false ;
00540
00541 return do_exit ;
00542 }
00543
00549 size_t
00550 CmdClient::readLine( string &msg )
00551 {
00552 size_t len = 0 ;
00553 char *buf = (char *) NULL ;
00554 buf =::readline( "BESClient> " ) ;
00555 if( buf && *buf )
00556 {
00557 len = strlen( buf ) ;
00558 #ifdef HAVE_READLINE_HISTORY
00559 add_history( buf ) ;
00560 #endif
00561 if( len > SIZE_COMMUNICATION_BUFFER )
00562 {
00563 cerr << __FILE__ << __LINE__
00564 <<
00565 ": incoming data buffer exceeds maximum capacity with lenght "
00566 << len << endl ;
00567 exit( 1 ) ;
00568 }
00569 else {
00570 msg = buf ;
00571 }
00572 }
00573 else {
00574 if( !buf )
00575 {
00576
00577
00578
00579
00580
00581 len = -1 ;
00582 }
00583 }
00584 if( buf )
00585 {
00586 free( buf ) ;
00587 buf = (char *)NULL ;
00588 }
00589 return len ;
00590 }
00591
00594 void
00595 CmdClient::displayHelp()
00596 {
00597 cout << endl ;
00598 cout << endl ;
00599 cout << "BES Command Line Client Help" << endl ;
00600 cout << endl ;
00601 cout << "Client commands available:" << endl ;
00602 cout <<
00603 " exit - exit the command line interface" <<
00604 endl ;
00605 cout << " help - display this help screen" <<
00606 endl ;
00607 cout <<
00608 " client suppress; - suppress output from the server" <<
00609 endl ;
00610 cout <<
00611 " client output to screen; - display server output to the screen"
00612 << endl ;
00613 cout <<
00614 " client output to <file>; - display server output to specified file"
00615 << endl ;
00616 cout <<
00617 " client load <file>; - load xml document from file"
00618 << endl ;
00619 cout << endl ;
00620 cout <<
00621 "Any commands beginning with 'client' must end with a semicolon" <<
00622 endl ;
00623 cout << endl ;
00624 cout << "To display the list of commands available from the server "
00625 << "please type the command 'show help;'" << endl ;
00626 cout << endl ;
00627 cout << endl ;
00628 }
00629
00634 bool
00635 CmdClient::isConnected()
00636 {
00637 if( _client )
00638 return _client->isConnected() ;
00639 return false ;
00640 }
00641
00644 void
00645 CmdClient::brokenPipe()
00646 {
00647 if( _client )
00648 _client->brokenPipe() ;
00649 }
00650
00657 void
00658 CmdClient::dump( ostream & strm ) const
00659 {
00660 strm << BESIndent::LMarg << "CmdClient::dump - ("
00661 << (void *) this << ")" << endl ;
00662 BESIndent::Indent() ;
00663 if( _client )
00664 {
00665 strm << BESIndent::LMarg << "client:" << endl ;
00666 BESIndent::Indent() ;
00667 _client->dump( strm ) ;
00668 BESIndent::UnIndent() ;
00669 }
00670 else
00671 {
00672 strm << BESIndent::LMarg << "client: null" << endl ;
00673 }
00674 strm << BESIndent::LMarg << "stream: " << (void *) _strm << endl ;
00675 strm << BESIndent::LMarg << "stream created? " << _strmCreated << endl ;
00676 BESIndent::UnIndent() ;
00677 }