#include <simgear/io/sg_socket_udp.hxx>
#include <simgear/math/sg_types.hxx>
#include <simgear/timing/timestamp.hxx>
+#include <simgear/misc/strutils.hxx>
#include <Network/protocol.hxx>
#include <Network/atc610x.hxx>
#include <Network/opengc.hxx>
#include <Network/nmea.hxx>
#include <Network/props.hxx>
+#include <Network/telnet.hxx>
#include <Network/pve.hxx>
#include <Network/ray.hxx>
#include <Network/rul.hxx>
// configure a port based on the config string
static FGProtocol *parse_port_config( const string& config )
{
- bool short_circuit = false;
-
- string::size_type begin, end;
-
- begin = 0;
-
SG_LOG( SG_IO, SG_INFO, "Parse I/O channel request: " << config );
- // determine protocol
- end = config.find(",", begin);
- if ( end == string::npos ) {
- return NULL; // dummy
+ vector<string> tokens = simgear::strutils::split( config, "," );
+ if (tokens.empty())
+ {
+ SG_LOG( SG_IO, SG_ALERT,
+ "Port configuration error: empty config string" );
+ return 0;
}
-
- string protocol = config.substr(begin, end - begin);
- begin = end + 1;
+
+ string protocol = tokens[0];
SG_LOG( SG_IO, SG_INFO, " protocol = " << protocol );
- FGProtocol *io;
- if ( protocol == "atc610x" ) {
- FGATC610x *atc610x = new FGATC610x;
- io = atc610x;
- short_circuit = true;
- cout << "here ..." << endl;
- } else if ( protocol == "atlas" ) {
- FGAtlas *atlas = new FGAtlas;
- io = atlas;
- } else if ( protocol == "opengc" ) {
- // char wait;
- // printf("Parsed opengc\n"); cin >> wait;
- FGOpenGC *opengc = new FGOpenGC;
- io = opengc;
- } else if ( protocol == "garmin" ) {
- FGGarmin *garmin = new FGGarmin;
- io = garmin;
- } else if ( protocol == "httpd" ) {
- // determine port
- string port = config.substr(begin);
- FGHttpd *httpd = new FGHttpd( atoi(port.c_str()) );
- io = httpd;
- short_circuit = true;
+ FGProtocol *io = 0;
+
+ try
+ {
+ if ( protocol == "atc610x" ) {
+ return new FGATC610x;
+ } else if ( protocol == "atlas" ) {
+ FGAtlas *atlas = new FGAtlas;
+ io = atlas;
+ } else if ( protocol == "opengc" ) {
+ // char wait;
+ // printf("Parsed opengc\n"); cin >> wait;
+ FGOpenGC *opengc = new FGOpenGC;
+ io = opengc;
+ } else if ( protocol == "garmin" ) {
+ FGGarmin *garmin = new FGGarmin;
+ io = garmin;
+ } else if ( protocol == "httpd" ) {
+ // determine port
+ string port = tokens[1];
+ return new FGHttpd( atoi(port.c_str()) );
#ifdef FG_JPEG_SERVER
- } else if ( protocol == "jpg-httpd" ) {
- // determine port
- string port = config.substr(begin);
- FGJpegHttpd *jpeg_httpd = new FGJpegHttpd( atoi(port.c_str()) );
- io = jpeg_httpd;
- short_circuit = true;
+ } else if ( protocol == "jpg-httpd" ) {
+ // determine port
+ string port = tokens[1];
+ return new FGJpegHttpd( atoi(port.c_str()) );
#endif
- } else if ( protocol == "joyclient" ) {
- FGJoyClient *joyclient = new FGJoyClient;
- io = joyclient;
- } else if ( protocol == "native" ) {
- FGNative *native = new FGNative;
- io = native;
- } else if ( protocol == "native_ctrls" ) {
- FGNativeCtrls *native_ctrls = new FGNativeCtrls;
- io = native_ctrls;
- } else if ( protocol == "native_fdm" ) {
- FGNativeFDM *native_fdm = new FGNativeFDM;
- io = native_fdm;
- } else if ( protocol == "nmea" ) {
- FGNMEA *nmea = new FGNMEA;
- io = nmea;
- } else if ( protocol == "props" ) {
- FGProps *props = new FGProps;
- io = props;
- } else if ( protocol == "pve" ) {
- FGPVE *pve = new FGPVE;
- io = pve;
- } else if ( protocol == "ray" ) {
- FGRAY *ray = new FGRAY;
- io = ray;
- } else if ( protocol == "rul" ) {
- FGRUL *rul = new FGRUL;
- io = rul;
- } else {
- return NULL;
+ } else if ( protocol == "joyclient" ) {
+ FGJoyClient *joyclient = new FGJoyClient;
+ io = joyclient;
+ } else if ( protocol == "native" ) {
+ FGNative *native = new FGNative;
+ io = native;
+ } else if ( protocol == "native_ctrls" ) {
+ FGNativeCtrls *native_ctrls = new FGNativeCtrls;
+ io = native_ctrls;
+ } else if ( protocol == "native_fdm" ) {
+ FGNativeFDM *native_fdm = new FGNativeFDM;
+ io = native_fdm;
+ } else if ( protocol == "nmea" ) {
+ FGNMEA *nmea = new FGNMEA;
+ io = nmea;
+ } else if ( protocol == "props" ) {
+ io = new FGProps();
+ } else if ( protocol == "telnet" ) {
+ io = new FGTelnet( tokens );
+ return io;
+ } else if ( protocol == "pve" ) {
+ FGPVE *pve = new FGPVE;
+ io = pve;
+ } else if ( protocol == "ray" ) {
+ FGRAY *ray = new FGRAY;
+ io = ray;
+ } else if ( protocol == "rul" ) {
+ FGRUL *rul = new FGRUL;
+ io = rul;
+ } else {
+ return NULL;
+ }
+ }
+ catch (FGProtocolConfigError& err)
+ {
+ SG_LOG( SG_IO, SG_ALERT, "Port configuration error: " << err.what() );
+ delete io;
+ return 0;
}
- if ( ! short_circuit ) {
- // determine medium
- end = config.find(",", begin);
- if ( end == string::npos ) {
- return NULL; // dummy
- }
-
- string medium = config.substr(begin, end - begin);
- begin = end + 1;
- SG_LOG( SG_IO, SG_INFO, " medium = " << medium );
-
- // determine direction
- end = config.find(",", begin);
- if ( end == string::npos ) {
- return NULL; // dummy
- }
-
- string direction = config.substr(begin, end - begin);
- begin = end + 1;
- io->set_direction( direction );
- SG_LOG( SG_IO, SG_INFO, " direction = " << direction );
-
- // determine hertz
- end = config.find(",", begin);
- if ( end == string::npos ) {
- return NULL; // dummy
- }
-
- string hertz_str = config.substr(begin, end - begin);
- begin = end + 1;
- double hertz = atof( hertz_str.c_str() );
- io->set_hz( hertz );
- SG_LOG( SG_IO, SG_INFO, " hertz = " << hertz );
-
- if ( medium == "serial" ) {
- // device name
- end = config.find(",", begin);
- if ( end == string::npos ) {
- return NULL;
- }
-
- string device = config.substr(begin, end - begin);
- begin = end + 1;
- SG_LOG( SG_IO, SG_INFO, " device = " << device );
-
- // baud
- string baud = config.substr(begin);
- SG_LOG( SG_IO, SG_INFO, " baud = " << baud );
-
- SGSerial *ch = new SGSerial( device, baud );
- io->set_io_channel( ch );
- } else if ( medium == "file" ) {
- // file name
- string file = config.substr(begin);
- SG_LOG( SG_IO, SG_INFO, " file name = " << file );
-
- SGFile *ch = new SGFile( file );
- io->set_io_channel( ch );
- } else if ( medium == "socket" ) {
- // hostname
- end = config.find(",", begin);
- if ( end == string::npos ) {
- return NULL;
- }
-
- string hostname = config.substr(begin, end - begin);
- begin = end + 1;
- SG_LOG( SG_IO, SG_INFO, " hostname = " << hostname );
-
- // port string
- end = config.find(",", begin);
- if ( end == string::npos ) {
- return NULL;
- }
-
- string port = config.substr(begin, end - begin);
- begin = end + 1;
- SG_LOG( SG_IO, SG_INFO, " port string = " << port );
-
- // socket style
- string style_str = config.substr(begin);
- SG_LOG( SG_IO, SG_INFO, " style string = " << style_str );
+ string medium = tokens[1];
+ SG_LOG( SG_IO, SG_INFO, " medium = " << medium );
+
+ string direction = tokens[2];
+ io->set_direction( direction );
+ SG_LOG( SG_IO, SG_INFO, " direction = " << direction );
+
+ string hertz_str = tokens[3];
+ double hertz = atof( hertz_str.c_str() );
+ io->set_hz( hertz );
+ SG_LOG( SG_IO, SG_INFO, " hertz = " << hertz );
+
+ if ( medium == "serial" ) {
+ // device name
+ string device = tokens[4];
+ SG_LOG( SG_IO, SG_INFO, " device = " << device );
+
+ // baud
+ string baud = tokens[5];
+ SG_LOG( SG_IO, SG_INFO, " baud = " << baud );
+
+ SGSerial *ch = new SGSerial( device, baud );
+ io->set_io_channel( ch );
+ } else if ( medium == "file" ) {
+ // file name
+ string file = tokens[4];
+ SG_LOG( SG_IO, SG_INFO, " file name = " << file );
+
+ SGFile *ch = new SGFile( file );
+ io->set_io_channel( ch );
+ } else if ( medium == "socket" ) {
+ string hostname = tokens[4];
+ string port = tokens[5];
+ string style = tokens[6];
+
+ SG_LOG( SG_IO, SG_INFO, " hostname = " << hostname );
+ SG_LOG( SG_IO, SG_INFO, " port = " << port );
+ SG_LOG( SG_IO, SG_INFO, " style = " << style );
- SGSocket *ch = new SGSocket( hostname, port, style_str );
- io->set_io_channel( ch );
- }
+ io->set_io_channel( new SGSocket( hostname, port, style ) );
}
return io;
// process any serial port work
void fgIOProcess() {
- FGProtocol *p;
-
// cout << "processing I/O channels" << endl;
static int inited = 0;
last = current;
}
- for ( int i = 0; i < (int)global_io_list.size(); ++i ) {
+ for ( unsigned int i = 0; i < global_io_list.size(); ++i ) {
// cout << " channel = " << i << endl;
- p = global_io_list[i];
+ FGProtocol* p = global_io_list[i];
if ( p->is_enabled() ) {
p->dec_count_down( interval );
version = "unknown version";
#endif
SG_LOG( SG_GENERAL, SG_INFO, "FlightGear: Version "
- << version << endl );
+ << version );
+ SG_LOG( SG_GENERAL, SG_INFO, "Built with " << SG_COMPILER_STR );
// Allocate global data structures. This needs to happen before
// we parse command line options
pve.cxx pve.hxx \
raw_ctrls.hxx \
ray.cxx ray.hxx \
- rul.cxx rul.hxx
+ rul.cxx rul.hxx \
+ telnet.cxx telnet.hxx
if OLD_AUTOMAKE
INCLUDES += -I$(top_srcdir) -I$(top_srcdir)/src
}
+void FGProtocol::set_direction( const string& d ) {
+ if ( d == "in" ) {
+ dir = SG_IO_IN;
+ } else if ( d == "out" ) {
+ dir = SG_IO_OUT;
+ } else if ( d == "bi" ) {
+ dir = SG_IO_BI;
+ } else {
+ dir = SG_IO_NONE;
+ }
+}
#include <simgear/compiler.h>
+#include <simgear/io/iochannel.hxx>
#include STL_STRING
#include <vector>
#define FG_MAX_MSG_SIZE 16384
-// forward declaration
-class SGIOChannel;
-
-
class FGProtocol {
private:
virtual bool close();
inline SGProtocolDir get_direction() const { return dir; }
- inline void set_direction( const string& d ) {
- if ( d == "in" ) {
- dir = SG_IO_IN;
- } else if ( d == "out" ) {
- dir = SG_IO_OUT;
- } else if ( d == "bi" ) {
- dir = SG_IO_BI;
- } else {
- dir = SG_IO_NONE;
- }
- }
+ void set_direction( const string& d );
inline double get_hz() const { return hz; }
inline void set_hz( double t ) { hz = t; }
typedef io_container::iterator io_iterator;
typedef io_container::const_iterator const_io_iterator;
+#include <stdexcept>
+SG_USING_STD(invalid_argument);
+
+//namespace flightgear { namespace network {
+class FGProtocolConfigError : public invalid_argument
+{
+public:
+ FGProtocolConfigError( const string& what_string )
+ : invalid_argument(what_string) {}
+};
+//}} // end namespace flightgear::network
+
#endif // _PROTOCOL_HXX
--- /dev/null
+// \file telnet.cx
+// Property telnet server class.
+//
+// Written by Bernie Bright, started May 2002.
+//
+// Copyright (C) 2002 Bernie Bright - bbright@bigpond.net.au
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+// $Id$
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <simgear/compiler.h>
+#include <simgear/debug/logstream.hxx>
+#include <simgear/misc/strutils.hxx>
+#include <simgear/misc/props.hxx>
+#include <simgear/misc/props_io.hxx>
+
+#include STL_STRSTREAM
+
+#include <Main/globals.hxx>
+#include <Main/viewmgr.hxx>
+
+#include <plib/netChat.h>
+
+#include "telnet.hxx"
+
+#if !defined(SG_HAVE_NATIVE_SGI_COMPILERS)
+SG_USING_STD(strstream);
+#endif
+
+/**
+ * Telnet connection class.
+ * This class represents a connection to a telnet-style client.
+ */
+class TelnetChannel : public netChat
+{
+ netBuffer buffer;
+
+ /**
+ * Current property node name.
+ */
+ string path;
+
+ enum Mode {
+ PROMPT,
+ DATA
+ };
+ Mode mode;
+
+public:
+ /**
+ * Constructor.
+ */
+ TelnetChannel();
+
+ /**
+ * Append incoming data to our request buffer.
+ *
+ * @param s Character string to append to buffer
+ * @param n Number of characters to append.
+ */
+ void collectIncomingData( const char* s, int n );
+
+ /**
+ * Process a complete request from the telnet client.
+ */
+ void foundTerminator();
+
+private:
+ /**
+ * Return a "Node no found" error message to the client.
+ */
+ void node_not_found_error( const string& node_name );
+
+ void view_cmd( const vector<string>& );
+};
+
+/**
+ *
+ */
+TelnetChannel::TelnetChannel()
+ : buffer(512),
+ path("/"),
+ mode(PROMPT)
+{
+ setTerminator( "\r\n" );
+}
+
+/**
+ *
+ */
+void
+TelnetChannel::collectIncomingData( const char* s, int n )
+{
+ buffer.append( s, n );
+}
+
+/**
+ *
+ */
+void
+TelnetChannel::node_not_found_error( const string& node_name )
+{
+ string error = "ERR Node \"";
+ error += node_name;
+ error += "\" not found.";
+ push( error.c_str() );
+ push( getTerminator() );
+}
+
+// return a human readable form of the value "type"
+static string
+getValueTypeString( const SGPropertyNode *node )
+{
+ string result;
+
+ if ( node == NULL )
+ {
+ return "unknown";
+ }
+
+ SGPropertyNode::Type type = node->getType();
+ if ( type == SGPropertyNode::UNSPECIFIED ) {
+ result = "unspecified";
+ } else if ( type == SGPropertyNode::NONE ) {
+ result = "none";
+ } else if ( type == SGPropertyNode::BOOL ) {
+ result = "bool";
+ } else if ( type == SGPropertyNode::INT ) {
+ result = "int";
+ } else if ( type == SGPropertyNode::LONG ) {
+ result = "long";
+ } else if ( type == SGPropertyNode::FLOAT ) {
+ result = "float";
+ } else if ( type == SGPropertyNode::DOUBLE ) {
+ result = "double";
+ } else if ( type == SGPropertyNode::STRING ) {
+ result = "string";
+ }
+
+ return result;
+}
+
+/**
+ * We have a command.
+ *
+ * TODO: possible future commands:
+ * panel <subcmd>
+ * panel load [path]
+ * panel mouse <button> up|down|click <x> <y>
+ * panel visible 0|1
+ * panel height -> h, Retrieve panel height
+ * panel width -> w, Retrieve panel width
+ * panel xoffset -> x, Retrieve panel x offset
+ * panel yoffset -> y, Retrieve panel y offset
+ *
+ * property <subcmd>
+ * property toggle <prop>
+ * property adjust <prop> <step> <offset> <factor> <min> <max> <wrap>
+ * property multiply <prop> <factor>
+ * property swap <prop1> <prop2>
+ * property scale <prop> <setting> <offset> <factor>
+ *
+ * view <subcmd>
+ * view next
+ * view prev
+ * view set <n>
+ * view current -> n, Retrieve index of current view
+ */
+void
+TelnetChannel::foundTerminator()
+{
+ const char* cmd = buffer.getData();
+ SG_LOG( SG_IO, SG_INFO, "processing command = \"" << cmd << "\"" );
+
+ vector<string> tokens = simgear::strutils::split( cmd );
+
+ SGPropertyNode* node = globals->get_props()->getNode( path.c_str() );
+
+ if (!tokens.empty())
+ {
+ string command = tokens[0];
+
+ if (command == "ls")
+ {
+ SGPropertyNode* dir = node;
+ if (tokens.size() == 2)
+ {
+ if (tokens[1][0] == '/')
+ {
+ dir = globals->get_props()->getNode( tokens[1].c_str() );
+ }
+ else
+ {
+ string s = path;
+ s += "/";
+ s += tokens[1];
+ dir = globals->get_props()->getNode( s.c_str() );
+ }
+
+ if (dir == 0)
+ {
+ node_not_found_error( tokens[1] );
+ goto prompt;
+ }
+ }
+
+ for (int i = 0; i < dir->nChildren(); i++)
+ {
+ SGPropertyNode * child = dir->getChild(i);
+ string name = child->getName();
+ string line = name;
+
+ if (dir->getChild( name.c_str(), 1 ))
+ {
+ char buf[16];
+ sprintf(buf, "[%d]", child->getIndex());
+ line += buf;
+ }
+
+ if ( child->nChildren() > 0 )
+ {
+ line += "/";
+ }
+ else
+ {
+ if (mode == PROMPT)
+ {
+ string value = dir->getStringValue( name.c_str(), "" );
+ line += " =\t'" + value + "'\t(";
+ line += getValueTypeString(
+ dir->getNode( name.c_str() ) );
+ line += ")";
+ }
+ }
+
+ line += getTerminator();
+ push( line.c_str() );
+ }
+ }
+ else if ( command == "dump" )
+ {
+ strstream buf;
+ if ( tokens.size() <= 1 )
+ {
+ writeProperties( buf, node );
+ push( buf.str() );
+ push( getTerminator() );
+ }
+ else
+ {
+ SGPropertyNode *child = node->getNode( tokens[1].c_str() );
+ if ( child )
+ {
+ writeProperties ( buf, child );
+ push( buf.str() );
+ push( getTerminator() );
+ }
+ else
+ {
+ node_not_found_error( tokens[1] );
+ }
+ }
+ }
+ else if ( command == "cd" )
+ {
+ if (tokens.size() == 2)
+ {
+ try
+ {
+ SGPropertyNode* child = node->getNode( tokens[1].c_str() );
+ if ( child )
+ {
+ node = child;
+ path = node->getPath();
+ }
+ else
+ {
+ node_not_found_error( tokens[1] );
+ }
+ }
+ catch (...)
+ {
+ // Ignore attempt to move past root node with ".."
+ }
+ }
+ }
+ else if ( command == "pwd" )
+ {
+ string ttt = node->getPath();
+ if (ttt.empty())
+ {
+ ttt = "/";
+ }
+
+ push( ttt.c_str() );
+ push( getTerminator() );
+ }
+ else if ( command == "get" || command == "show" )
+ {
+ if ( tokens.size() == 2 )
+ {
+ string tmp;
+ string value = node->getStringValue ( tokens[1].c_str(), "" );
+ if ( mode == PROMPT )
+ {
+ tmp = tokens[1];
+ tmp += " = '";
+ tmp += value;
+ tmp += "' (";
+ tmp += getValueTypeString(
+ node->getNode( tokens[1].c_str() ) );
+ tmp += ")\n";
+ }
+ else
+ {
+ tmp = value + "\n";
+ }
+ push( tmp.c_str() );
+ }
+ }
+ else if ( command == "set" )
+ {
+ if ( tokens.size() == 3 )
+ {
+ node->getNode( tokens[1].c_str(), true )->setStringValue(tokens[2].c_str());
+
+ if ( mode == PROMPT )
+ {
+ // now fetch and write out the new value as confirmation
+ // of the change
+ string value = node->getStringValue ( tokens[1].c_str(), "" );
+ string tmp = tokens[1] + " = '" + value + "' (";
+ tmp += getValueTypeString( node->getNode( tokens[1].c_str() ) );
+ tmp += ")\n";
+ push( tmp.c_str() );
+ }
+ }
+ }
+ else if (command == "quit")
+ {
+ close();
+ shouldDelete();
+ return;
+ }
+ else if ( command == "data" )
+ {
+ mode = DATA;
+ }
+ else if ( command == "prompt" )
+ {
+ mode = PROMPT;
+ }
+ else if ( command == "view" )
+ {
+ view_cmd( tokens );
+ }
+// else if ( command == "panel" )
+// {
+// panel_cmd( tokens );
+// }
+// else if ( command == "property" )
+// {
+// property_cmd( tokens );
+// }
+ else
+ {
+ const char* msg = "
+Valid commands are:
+
+cd <dir> cd to a directory, '..' to move back
+data switch to raw data mode
+dump dump current state (in xml)
+get <var> show the value of a parameter
+help show this help message
+ls [<dir>] list directory
+prompt switch to interactive mode (default)
+pwd display your current path
+quit terminate connection
+set <var> <val> set <var> to a new <val>
+show <var> synonym for get
+view next display next view
+view prev display prev view
+view set <n> display view 'n'
+view get return current view index
+view current return current view index
+";
+ push( msg );
+ }
+ }
+
+ prompt:
+ if (mode == PROMPT)
+ {
+ string prompt = node->getPath();
+ if (prompt.empty())
+ {
+ prompt = "/";
+ }
+ prompt += "> ";
+ push( prompt.c_str() );
+ }
+
+ buffer.remove();
+}
+
+/**
+ *
+ */
+void
+TelnetChannel::view_cmd( const vector<string>& tokens )
+{
+ if (tokens.size() <= 1)
+ {
+ // ERROR: no sub-command
+ return;
+ }
+ string subcmd = tokens[1];
+
+ if (subcmd == "next")
+ {
+ globals->get_current_view()->setHeadingOffset_deg(0.0);
+ globals->get_viewmgr()->next_view();
+ }
+ else if (subcmd == "prev")
+ {
+ globals->get_current_view()->setHeadingOffset_deg(0.0);
+ globals->get_viewmgr()->prev_view();
+ }
+ else if (subcmd == "set")
+ {
+ if (tokens.size() == 3)
+ {
+ int i = atoi( tokens[2].c_str() );
+ if (0 >= i && i < globals->get_viewmgr()->size())
+ {
+ globals->get_current_view()->setHeadingOffset_deg(0.0);
+ globals->get_viewmgr()->set_view(i);
+ globals->get_viewmgr()->copyToCurrent();
+ }
+ }
+ }
+ else if (subcmd == "get" || subcmd == "current")
+ {
+ int i = globals->get_viewmgr()->get_current();
+ char buf[16];
+ snprintf( buf, sizeof(buf), "%d", i );
+ push( buf );
+ push( getTerminator() );
+ }
+ else
+ {
+ // ERROR: invalid subcommand.
+ }
+}
+
+/**
+ *
+ */
+FGTelnet::FGTelnet( const vector<string>& tokens )
+{
+ if (tokens.size() != 2)
+ {
+ throw FGProtocolConfigError( "FGProps: expected 1 argument, <port>" );
+ }
+
+ port = atoi( tokens[1].c_str() );
+}
+
+/**
+ *
+ */
+FGTelnet::~FGTelnet()
+{
+}
+
+/**
+ *
+ */
+bool
+FGTelnet::open()
+{
+ if ( is_enabled() )
+ {
+ SG_LOG( SG_IO, SG_ALERT, "This shouldn't happen, but the channel "
+ << "is already in use, ignoring" );
+ return false;
+ }
+
+ netChannel::open();
+ netChannel::bind( "", port );
+ netChannel::listen( 5 );
+ SG_LOG( SG_IO, SG_INFO, "Telnet server started on port " << port );
+
+ set_hz( 5 ); // default to processing requests @ 5Hz
+ set_enabled( true );
+ return true;
+}
+
+/**
+ *
+ */
+bool
+FGTelnet::close()
+{
+ return true;
+}
+
+/**
+ *
+ */
+bool
+FGTelnet::process()
+{
+ netChannel::poll();
+ return true;
+}
+
+/**
+ *
+ */
+void
+FGTelnet::handleAccept()
+{
+ netAddress addr;
+ int handle = accept( &addr );
+ SG_LOG( SG_IO, SG_INFO, "Telnet server accepted connection from "
+ << addr.getHost() << ":" << addr.getPort() );
+ TelnetChannel* channel = new TelnetChannel();
+ channel->setHandle( handle );
+}
--- /dev/null
+// \file telnet.hxx
+// Property server class.
+//
+// Written by Bernie Bright, started May 2002.
+//
+// Copyright (C) 2002 Bernie Bright - bbright@bigpond.net.au
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+// $Id$
+
+#ifndef TELNET_HXX_INCLUDED
+#define TELNET_HXX_INCLUDED 1
+
+#include <simgear/compiler.h>
+#include STL_STRING
+#include <vector>
+
+SG_USING_STD(string);
+SG_USING_STD(vector);
+
+#include <plib/netChannel.h>
+
+#include "protocol.hxx"
+
+/**
+ * Property server class.
+ * This class provides a telnet-like server for remote access to
+ * FlightGear properties.
+ */
+class FGTelnet : public FGProtocol,
+ public netChannel
+{
+private:
+
+ /**
+ * Server port to listen on.
+ */
+ int port;
+
+public:
+ /**
+ * Create a new TCP server.
+ *
+ * @param tokens Tokenized configuration parameters
+ */
+ FGTelnet( const vector<string>& tokens );
+
+ /**
+ * Destructor.
+ */
+ ~FGTelnet();
+
+ /**
+ * Start the telnet server.
+ */
+ bool open();
+
+ /**
+ * Process network activity.
+ */
+ bool process();
+
+ /**
+ *
+ */
+ bool close();
+
+ /**
+ * Accept a new client connection.
+ */
+ void handleAccept();
+
+};
+
+#endif //TELNET_HXX_INCLUDED
+