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 "CmdPretty.h"
00087 #include "PPTClient.h"
00088 #include "BESDebug.h"
00089 #include "BESStopWatch.h"
00090 #include "BESError.h"
00091
00092 CmdClient::~CmdClient()
00093 {
00094 if( _strmCreated && _strm )
00095 {
00096 _strm->flush() ;
00097 delete _strm ;
00098 _strm = 0 ;
00099 }
00100 else if( _strm )
00101 {
00102 _strm->flush( ) ;
00103 }
00104 if( _client )
00105 {
00106 delete _client ;
00107 _client = 0 ;
00108 }
00109 }
00110
00125 void
00126 CmdClient::startClient( const string & host, int portVal, int timeout )
00127 {
00128 _client = new PPTClient( host, portVal, timeout ) ;
00129 _client->initConnection() ;
00130 }
00131
00141 void
00142 CmdClient::startClient( const string & unixStr, int timeout )
00143 {
00144 _client = new PPTClient( unixStr, timeout ) ;
00145 _client->initConnection() ;
00146 }
00147
00156 void
00157 CmdClient::shutdownClient()
00158 {
00159 if( _client )
00160 _client->closeConnection() ;
00161 }
00162
00179 void
00180 CmdClient::setOutput( ostream * strm, bool created )
00181 {
00182 if( _strmCreated && _strm )
00183 {
00184 _strm->flush() ;
00185 delete _strm ;
00186 }
00187 else if( _strm )
00188 {
00189 _strm->flush() ;
00190 }
00191 _strm = strm ;
00192 _strmCreated = created ;
00193 }
00194
00206 void
00207 CmdClient::executeClientCommand( const string & cmd )
00208 {
00209 string suppress = "suppress" ;
00210 if( cmd.compare( 0, suppress.length(), suppress ) == 0 )
00211 {
00212 setOutput( NULL, false ) ;
00213 return ;
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 ;
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 executeCommands( fstrm, 1 ) ;
00259 }
00260
00261 return ;
00262 }
00263
00264 cerr << "Improper client command " << cmd << endl ;
00265 }
00266
00279 void
00280 CmdClient::executeCommand( const string &cmd, int repeat )
00281 {
00282 string client = "client" ;
00283 if( cmd.compare( 0, client.length(), client ) == 0 )
00284 {
00285 executeClientCommand( cmd.substr( client.length() + 1 ) ) ;
00286 }
00287 else
00288 {
00289 if( repeat < 1 ) repeat = 1 ;
00290 for( int i = 0; i < repeat; i++ )
00291 {
00292 BESDEBUG( "cmdln", "cmdclient sending " << cmd << endl ) ;
00293 BESStopWatch *sw = 0 ;
00294 if( BESISDEBUG( "timing" ) )
00295 {
00296 sw = new BESStopWatch() ;
00297 sw->start() ;
00298 }
00299
00300 map<string,string> extensions ;
00301 _client->send( cmd, extensions ) ;
00302
00303 BESDEBUG( "cmdln", "cmdclient receiving " << endl ) ;
00304
00305 bool done = false ;
00306 ostringstream *show_stream = 0 ;
00307 while( !done )
00308 {
00309 if( CmdTranslation::is_show() )
00310 {
00311 if( !show_stream )
00312 {
00313 show_stream = new ostringstream ;
00314 }
00315 }
00316 if( show_stream )
00317 {
00318 done = _client->receive( extensions, show_stream ) ;
00319 }
00320 else
00321 {
00322 done = _client->receive( extensions, _strm ) ;
00323 }
00324 if( extensions["status"] == "error" )
00325 {
00326
00327
00328 _strm->flush() ;
00329
00330
00331
00332 if( _isInteractive )
00333 {
00334 CmdTranslation::set_show( true ) ;
00335 }
00336
00337 }
00338 }
00339 if( show_stream )
00340 {
00341 CmdPretty::make_pretty( show_stream->str(), *_strm ) ;
00342 delete show_stream ;
00343 show_stream = 0 ;
00344 }
00345 if( BESDebug::IsSet( "cmdln" ) )
00346 {
00347 BESDEBUG( "cmdln", "extensions:" << endl ) ;
00348 map<string,string>::const_iterator i = extensions.begin() ;
00349 map<string,string>::const_iterator e = extensions.end() ;
00350 for( ; i != e; i++ )
00351 {
00352 BESDEBUG( "cmdln", " " << (*i).first << " = "
00353 << (*i).second << endl ) ;
00354 }
00355 BESDEBUG( "cmdln", "cmdclient done receiving " << endl ) ;
00356 }
00357 if( BESISDEBUG( "timing" ) )
00358 {
00359 if( sw && sw->stop() )
00360 {
00361 BESDEBUG( "timing", "cmdclient - executed \""
00362 << cmd << "\" in " << sw->seconds()
00363 << " seconds and " << sw->microseconds()
00364 << " microseconds" << endl ) ;
00365 }
00366 else
00367 {
00368 BESDEBUG( "timing", "cmdclient - executed \"" << cmd
00369 << "\" - no timing available"
00370 << endl ) ;
00371 }
00372 }
00373
00374 _strm->flush() ;
00375 delete sw ;
00376 sw = 0 ;
00377 }
00378 }
00379 }
00380
00398 void
00399 CmdClient::executeCommands( const string &cmd_list, int repeat )
00400 {
00401 _isInteractive = true ;
00402 if( repeat < 1 ) repeat = 1 ;
00403
00404 CmdTranslation::set_show( false ) ;
00405 try
00406 {
00407 string doc = CmdTranslation::translate( cmd_list ) ;
00408 if( !doc.empty() )
00409 {
00410 this->executeCommand( doc, repeat ) ;
00411 }
00412 }
00413 catch( BESError &e )
00414 {
00415 CmdTranslation::set_show( false ) ;
00416 _isInteractive = false ;
00417 throw e ;
00418 }
00419 CmdTranslation::set_show( false ) ;
00420 _isInteractive = false ;
00421 }
00422
00441 void
00442 CmdClient::executeCommands( ifstream & istrm, int repeat )
00443 {
00444 _isInteractive = false ;
00445 if( repeat < 1 ) repeat = 1 ;
00446 for( int i = 0; i < repeat; i++ )
00447 {
00448 istrm.clear( ) ;
00449 istrm.seekg( 0, ios::beg ) ;
00450 string cmd ;
00451 while( !istrm.eof() )
00452 {
00453 char line[4096] ;
00454 line[0] = '\0' ;
00455 istrm.getline( line, 4096, '\n' ) ;
00456 cmd += line ;
00457 }
00458 this->executeCommand( cmd, 1 ) ;
00459 }
00460 }
00461
00481 void
00482 CmdClient::interact()
00483 {
00484 _isInteractive = true ;
00485
00486 cout << endl << endl
00487 << "Type 'exit' to exit the command line client and 'help' or '?' "
00488 << "to display the help screen" << endl << endl ;
00489
00490 bool done = false ;
00491 while( !done )
00492 {
00493 string message = "" ;
00494 size_t len = this->readLine( message ) ;
00495 if( len == -1 || message == "exit" || message == "exit;" )
00496 {
00497 done = true ;
00498 }
00499 else if( message == "help" || message == "help;" || message == "?" )
00500 {
00501 this->displayHelp() ;
00502 }
00503 else if( message.length() > 6 && message.substr( 0, 6 ) == "client" )
00504 {
00505 this->executeCommand( message, 1 ) ;
00506 }
00507 else if( len != 0 && message != "" )
00508 {
00509 CmdTranslation::set_show( false ) ;
00510 try
00511 {
00512 string doc = CmdTranslation::translate( message ) ;
00513 if( !doc.empty() )
00514 {
00515 this->executeCommand( doc, 1 ) ;
00516 }
00517 }
00518 catch( BESError &e )
00519 {
00520 CmdTranslation::set_show( false ) ;
00521 _isInteractive = false ;
00522 throw e ;
00523 }
00524 CmdTranslation::set_show( false ) ;
00525 }
00526 }
00527 _isInteractive = false ;
00528 }
00529
00535 size_t
00536 CmdClient::readLine( string &msg )
00537 {
00538 size_t len = 0 ;
00539 char *buf = (char *) NULL ;
00540 buf =::readline( "BESClient> " ) ;
00541 if( buf && *buf )
00542 {
00543 len = strlen( buf ) ;
00544 #ifdef HAVE_READLINE_HISTORY
00545 add_history( buf ) ;
00546 #endif
00547 if( len > SIZE_COMMUNICATION_BUFFER )
00548 {
00549 cerr << __FILE__ << __LINE__
00550 <<
00551 ": incoming data buffer exceeds maximum capacity with lenght "
00552 << len << endl ;
00553 exit( 1 ) ;
00554 }
00555 else {
00556 msg = buf ;
00557 }
00558 }
00559 else {
00560 if( !buf )
00561 {
00562
00563
00564
00565
00566
00567 len = -1 ;
00568 }
00569 }
00570 if( buf )
00571 {
00572 free( buf ) ;
00573 buf = (char *)NULL ;
00574 }
00575 return len ;
00576 }
00577
00580 void
00581 CmdClient::displayHelp()
00582 {
00583 cout << endl ;
00584 cout << endl ;
00585 cout << "BES Command Line Client Help" << endl ;
00586 cout << endl ;
00587 cout << "Client commands available:" << endl ;
00588 cout <<
00589 " exit - exit the command line interface" <<
00590 endl ;
00591 cout << " help - display this help screen" <<
00592 endl ;
00593 cout <<
00594 " client suppress; - suppress output from the server" <<
00595 endl ;
00596 cout <<
00597 " client output to screen; - display server output to the screen"
00598 << endl ;
00599 cout <<
00600 " client output to <file>; - display server output to specified file"
00601 << endl ;
00602 cout <<
00603 " client load <file>; - load xml document from file"
00604 << endl ;
00605 cout << endl ;
00606 cout <<
00607 "Any commands beginning with 'client' must end with a semicolon" <<
00608 endl ;
00609 cout << endl ;
00610 cout << "To display the list of commands available from the server "
00611 << "please type the command 'show help;'" << endl ;
00612 cout << endl ;
00613 cout << endl ;
00614 }
00615
00620 bool
00621 CmdClient::isConnected()
00622 {
00623 if( _client )
00624 return _client->isConnected() ;
00625 return false ;
00626 }
00627
00630 void
00631 CmdClient::brokenPipe()
00632 {
00633 if( _client )
00634 _client->brokenPipe() ;
00635 }
00636
00643 void
00644 CmdClient::dump( ostream & strm ) const
00645 {
00646 strm << BESIndent::LMarg << "CmdClient::dump - ("
00647 << (void *) this << ")" << endl ;
00648 BESIndent::Indent() ;
00649 if( _client )
00650 {
00651 strm << BESIndent::LMarg << "client:" << endl ;
00652 BESIndent::Indent() ;
00653 _client->dump( strm ) ;
00654 BESIndent::UnIndent() ;
00655 }
00656 else
00657 {
00658 strm << BESIndent::LMarg << "client: null" << endl ;
00659 }
00660 strm << BESIndent::LMarg << "stream: " << (void *) _strm << endl ;
00661 strm << BESIndent::LMarg << "stream created? " << _strmCreated << endl ;
00662 BESIndent::UnIndent() ;
00663 }