namespace senf {
namespace term {
+ /** \brief Abstract terminal interface
+
+ This abstract interface base class provides an abstract interface to a terminal. There are
+ two parts to this interface:
+
+ \li The interface which allows the terminal user to get information about the terminal
+ \li The interface which allows the terminal to send messages to the terminal user
+
+ The first part is implemented by providing abstract virtual members in AbstractTerminal. To
+ allow the terminal to send messages to the terminal user, the terminal user implements the
+ AbstractTerminal::Callbacks interface. The terminal user must register himself with the
+ AbstractTerminal by calling setCallbacks(). Afterwards, the AbstractTerminal implementation
+ will send calls to the terminal user via the AbstractTerminal::Callbacks API.
+ */
struct AbstractTerminal
{
+ /** \brief AbstractTerminal callbacks
+
+ \see AbastractTerminal
+ */
struct Callbacks {
virtual ~Callbacks() {}
- virtual bool cb_init() = 0;
- virtual void cb_charReceived(char ch) = 0;
- virtual void cb_windowSizeChanged() = 0;
+ virtual bool cb_init() = 0; ///< Called after terminal initialization is complete
+ /**< This member may return \c false. In this case, the
+ terminal setup is considered to have failed. */
+ virtual void cb_charReceived(char ch) = 0; ///< Called whenever a char is received
+ virtual void cb_windowSizeChanged() = 0; ///< Called when the terminal window is changed
};
virtual ~AbstractTerminal() {}
- virtual void setCallbacks(Callbacks & cb) = 0;
+ virtual void setCallbacks(Callbacks & cb) = 0; /// Register terminal callbacks
- virtual std::string terminalType() = 0;
- virtual unsigned width() = 0;
- virtual unsigned height() = 0;
+ virtual std::string terminalType() = 0; ///< Get the terminal type
+ virtual unsigned width() = 0; ///< Get current terminal window width
+ virtual unsigned height() = 0; ///< Get current terminal window height
- virtual void write(char ch) = 0;
+ virtual void write(char ch) = 0; ///< Write character to terminal
};
}}
GENERATE_TAGFILE = doc/Console.tag
EXAMPLE_PATH = .
EXCLUDE = telnetServer.cc
+ALPHABETICAL_INDEX = NO
TAGFILES = \
"$(TOPDIR)/Socket/doc/Socket.tag" \
namespace senf {
namespace term {
+ /** \brief Provide editor support terminal functionality
+
+ This base class utilizes an arbitrary AbstractTerminal and provides terminfo based
+ terminal navigation and key parsing.
+
+ All navigation is relative to the current line. The display area can then be extended
+ downwards up to a maximum of height() lines. Resetting this extended display area will
+ return to a one line area containing only the top line.
+
+ All navigation is restricted to a width() x height() area. The last column may not be
+ written to since auto-margin terminals will move the cursor to the next line when writing to
+ that column.
+
+ This base class calls v_keyReceived() which must be defined in a derived class whenever a
+ key is fully parsed.
+ */
class BaseEditor
: public AbstractTerminal::Callbacks
{
unsigned height(); ///< Return current screen height
protected:
- virtual bool cb_init();
+ virtual bool cb_init(); ///< Called when terminal is initialized
virtual void cb_windowSizeChanged();
+ ///< Called whenever the terminal window size changes
+#ifndef DOXYGEN
private:
- virtual void v_keyReceived(keycode_t key) = 0;
+#endif
+ virtual void v_keyReceived(keycode_t key) = 0; ///< Called whenever a key is received
+ private:
virtual void cb_charReceived(char c);
void keySequenceTimeout();
unsigned displayHeight_;
unsigned line_;
};
+
+ /** \brief Single line interactive text editor
+
+ LineEditor implements a single-line input widget on an arbitrary AbstractTerminal.
+
+ \li It supports all the customary editing functions
+ \li It is possible to arbitrarily assign functions to keys via a key map
+ \li LineEditor has builtin TAB completion support
+ \li The LineEditor has a built-in history
+ \li The LineEditor supports an arbitrary auxiliary display area below the input line
+ \li The LineEditor has hide() / show() support to allow editing to be temporarily
+ interrupted.
+
+ The LineEditor will query the user for an input line. When the user accepts a line,
+ LineEditor will call a user callback function. After the callback has been called, the
+ editor is disabled. To accept a new input line, call show().
+
+ \section editor_keymap The editor key map
+
+ Keys are defined in the keymap using defineKey(). The default bindings are:
+
+ <table class="senf">
+ <tr><td>\c Return</td> <td>bindings::accept</td></tr>
+ <tr><td>\c Right</td> <td>bindings::forwardChar</td></tr>
+ <tr><td>\c Left</td> <td>bindings::backwardChar</td></tr>
+ <tr><td>\c Up</td> <td>bindings::prevHistory</td></tr>
+ <tr><td>\c Down</td> <td>bindings::nextHistory</td></tr>
+ <tr><td>\c Backspace</td> <td>bindings::backwardDeleteChar</td></tr>
+ <tr><td>\c Delete</td> <td>bindings::deleteChar</td></tr>
+ <tr><td>\c Home</td> <td>bindings::beginningOfLine</td></tr>
+ <tr><td>\c End</td> <td>bindings::endOfLine</td></tr>
+ <tr><td>\c Ctrl-K</td> <td>bindings::deleteToEndOfLine</td></tr>
+ <tr><td>\c Ctrl-A</td> <td>bindings::beginningOfLine</td></tr>
+ <tr><td>\c Ctrl-E</td> <td>bindings::endOfLine</td></tr>
+ <tr><td>\c Ctrl-D</td> <td>bindings::deleteChar</td></tr>
+ <tr><td>\c Ctrl-C</td> <td>bindings::restartEdit</td></tr>
+ <tr><td>\c Ctrl-L</td> <td>bindings::clearScreen</td></tr>
+ </table>
+
+ See the senf::term::bindings namespace for a list of all default provided key binding
+ functions.
+
+
+ \section editor_complete Completion suppoprt
+
+ Completion support is provided by senf::term::bindings::complete(). To use the completer,
+ you need to implement a completion function and pass it as second argument to
+ bindings::complete():
+
+ \code
+ void myCompleter(senf::term::LineEditor & editor, unsigned b, unsigned e,
+ std::vector<std::string> & completions)
+ {
+ // Get text to complete
+ std::string text (editor.text().substr(b, e-b));
+
+ // Return possible completions in 'completions' array
+ completions.push_back( ... );
+ }
+
+ senf::term::LineEditor editor (...);
+ editor.defineKey(senf::term::KeyParser::TAB,
+ boost::bind(&senf::term::bindings::complete, _1, &myCompleter));
+ \endcode
+
+ When \c myCompleter is a class member, use senf::membind() and pass this instead of \c
+ &myCompleter to \c boost::bind() and thus to senf::term::bindings::complete.
+
+
+ \section editor_auxarea The aux display area
+
+ The auxiliary display area is accessed using auxDisplay() and clearAuxDisplay(). The aux
+ display area is \e cleared \e before each new key is processed. Therefore it is only
+ temporary. The aux display area however will survive hide() / show().
+
+ \section editor_hideshow Temporarily disabling the editor
+
+ Calling hide() will temporarily disable the editor. All editor display will be
+ removed. Calling show() will redisplay the editor in it's current state including the aux
+ display area.
+ */
class LineEditor
: public BaseEditor
{
///////////////////////////////////////////////////////////////////////////
// Types
- typedef boost::function<void (LineEditor&)> KeyBinding;
+ typedef boost::function<void (LineEditor&)> KeyBinding; ///< Type of a key binding function
typedef boost::function<void (std::string const &)> AcceptCallback;
+ ///< Callback function type
static unsigned const MAX_HISTORY_SIZE = 1024u;
///////////////////////////////////////////////////////////////////////////
LineEditor(AbstractTerminal & terminal, AcceptCallback cb);
+ ///< Create a LineEditor
+ /**< \parm[in] terminal abstract terminal interface
+ \parm[in] cb callback to call for complete input
+ line */
///////////////////////////////////////////////////////////////////////////
- void prompt(std::string const & text);
+ void prompt(std::string const & text); ///< Set prompt string
void set(std::string const & text, unsigned pos = 0u);
+ ///< Set edit buffer contents
+ /**< The edit buffer contents will be replaced by \a
+ text. The cursor will be placed at position \a pos
+ within this text. */
- // Overall edit control
- void show();
- void hide();
- void accept();
- void clear();
- void redisplay();
- void forceRedisplay();
-
- // Cursor and display movement
- void gotoChar(unsigned n);
- void scrollTo(unsigned n);
+ ///\name Overall edit control
+ ///\{
+
+ void show(); ///< Enable editor widget
+ void hide(); ///< Disable editor widget
+ void accept(); ///< Accept current user input and call the accept callback
+ void clear(); ///< Clear editor buffer
+ void redisplay(); ///< Mark the editor buffer for redisplay
+ void forceRedisplay(); ///< Redisplay the editor buffer \e now
+
+ ///\}
+
+ ///\name Cursor and display movement
+ ///\{
+
+ void gotoChar(unsigned n); ///< Move cursor to position \a n
+ void scrollTo(unsigned n); ///< Move positon \n to beginning of display line
+
+ ///\}
+
+ ///\name Text manipulation
+ ///\{
+
+ void deleteChar(unsigned n=1); ///< Delete \a n characters at point
+ void insert(char ch); ///< Insert \a ch at point
+ void insert(std::string const & text); ///< Insert \a text at point
- // Text manipulation
- void deleteChar(unsigned n=1);
- void insert(char ch);
- void insert(std::string const & text);
+ ///\}
- // History
- void pushHistory(std::string const & text);
- void prevHistory();
- void nextHistory();
+ ///\name History
+ ///\{
+
+ void pushHistory(std::string const & text); ///< Add string \a text to history
+ void prevHistory(); ///< Switch to previous history entry
+ void nextHistory(); ///< Switch to next history entry
+
+ ///\}
+
+ ///\name Aux Display
+ ///\{
- // Aux Display
void auxDisplay(int line, std::string const & text);
- unsigned maxAuxDisplayHeight();
- void clearAuxDisplay();
+ ///< Display \a text on aux display line \a lilne
+ unsigned maxAuxDisplayHeight(); ///< Get maximum height of the aux display area
+ void clearAuxDisplay(); ///< Clear the aux display area
+
+ ///\}
+
+ ///\name Get information
+ ///\{
- // Get information
- std::string const & text();
- unsigned point();
- unsigned displayPos();
- keycode_t lastKey();
+ std::string const & text(); ///< Get current editor buffer contents
+ unsigned point(); ///< Get current cursor position
+ unsigned displayPos(); ///< Get current display position
+ keycode_t lastKey(); ///< Get last key code received
+
+ ///\}
+
+ ///\name Key bindings
+ ///\{
- // Key bindings
void defineKey(keycode_t key, KeyBinding binding);
- void unsetKey(keycode_t key);
+ ///< Bind key \a key to \a binding
+ void unsetKey(keycode_t key); ///< Remove all bindings for \a key
+
+ ///\}
private:
virtual bool cb_init();
AuxDisplay auxDisplay_;
};
+/** \brief LineEditor key bindings
+ */
namespace bindings {
- void selfInsertCommand (LineEditor & editor);
- void forwardChar (LineEditor & editor);
- void backwardChar (LineEditor & editor);
- void accept (LineEditor & editor);
- void backwardDeleteChar (LineEditor & editor);
- void deleteChar (LineEditor & editor);
- void beginningOfLine (LineEditor & editor);
- void endOfLine (LineEditor & editor);
- void deleteToEndOfLine (LineEditor & editor);
- void restartEdit (LineEditor & editor);
- void prevHistory (LineEditor & editor);
- void nextHistory (LineEditor & editor);
- void clearScreen (LineEditor & editor);
+ void selfInsertCommand (LineEditor & editor); ///< Insert key as literal character
+ void forwardChar (LineEditor & editor); ///< Move one char forward
+ void backwardChar (LineEditor & editor); ///< Move one char backwards
+ void accept (LineEditor & editor); ///< Accept input line
+ void backwardDeleteChar (LineEditor & editor); ///< Delete char before cursor
+ void deleteChar (LineEditor & editor); ///< Delete char at cursor
+ void beginningOfLine (LineEditor & editor); ///< Move to beginning of line
+ void endOfLine (LineEditor & editor); ///< Move to end of line
+ void deleteToEndOfLine (LineEditor & editor); ///< Delete from cursor to end of line
+ void restartEdit (LineEditor & editor); ///< Clear edit buffer and restart edit
+ void prevHistory (LineEditor & editor); ///< Move to previous history entry
+ void nextHistory (LineEditor & editor); ///< Move to next history entry
+ void clearScreen (LineEditor & editor); ///< Clear screen and redisplay editor
typedef boost::function<void (LineEditor &, unsigned b, unsigned e, std::vector<std::string> &)> Completer;
void complete (LineEditor & editor, Completer completer);
+ ///< Complete text at cursor
+ /**< This function calls \a completer to find the list of
+ possible completions for the text between \a b and \a e
+ (as passed to the completer). The completer must add
+ all possible completions to the completions vector.
+
+ \see \ref editor_complete */
}
--- /dev/null
+// $Id$
+//
+// Copyright (C) 2009
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+// Stefan Bund <g0dil@berlios.de>
+//
+// 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.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \mainpage Terminal utility functions
+
+ The Termlib module provides several facilities to help working with terminal I/O
+
+ \autotoc
+
+ \section termlib_sect_telnet Telnet protocol implementation
+ \seechapter \ref telnet_group
+
+ This is a partial implementation of the telnet protokoll. It provides enough functionality to
+ provide terminal access.
+
+ \section termlib_sect_terminfo Terminfo database access
+ \seechapter \ref terminfo_group
+
+ The senf::term::Terminfo class provides access to the termios database.
+
+ \section termlib_sect_editor Simple line-oriented text editor
+ \seechapter senf::term::LineEditor
+
+ Using the termios functionality, this class implements simple line editing
+
+ */
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// mode: flyspell
+// mode: auto-fill
+// End:
pendingRequests_ (0u),
requestTimeout_ (ClockService::milliseconds(DEFAULT_REQUEST_TIMEOUT_MS)),
timeout_ ("senf::term::BaseTelnetProtocol::timeout", 0)
-{}
+{
+ SENF_ASSERT( false );
+}
prefix_ void senf::term::BaseTelnetProtocol::write(std::string const & s)
{
namespace senf {
namespace term {
- /** \brief Telnet server
+ /** \defgroup telnet_group Telnet protocol
- \see
- <a href="http://tools.ietf.org/html/rfc854">RFC 854</a> The Telnet protocol \n
- <a href="http://tools.ietf.org/html/rfc854">RFC 855</a> Telnet option specifications
+ The telnet protocol implementation is based on the relevant RFCs:
+
+ \li <a href="http://tools.ietf.org/html/rfc854">RFC 854</a> The Telnet protocol
+ \li <a href="http://tools.ietf.org/html/rfc854">RFC 855</a> Telnet option specifications
+
+ BaseTelnetProtocol provides the basic protocol implementation with generic telnet option
+ support. Several other classes provide additional support for further telnet options:
+
+ \li telnethandler::TerminalType provides support for the TERMINAL_TYPE option
+ \li telnethandler::NAWS provides support for the NAWS (Negotiation About Window Size) option
+
+ There are some symbolic constants for telnet option in the senf::term::telnetopt namespace.
+ */
+
+ /** \brief Telnet protocol implementation
+
+ This class implements the basic telnet protocol. It provides option parsing and negotiation
+ and implements the necessary character quoting.
+
+ This class is a base class. Several virtual function hooks are provided which will be called
+ by the protocol implementation.
+
+ The telnet protocol implementation is symmetric: At this level, there is no difference
+ between a telnet client and a telnet server.
+
+ This telnet protocol base class integrates with the SENF Scheduler, it relies on the
+ scheduler main loop to be active.
+
+ \section telnethandlers Telnet option handlers
+
+ To support complex telnet option which require subnegotiation, TelnetHandler's are
+ provided. A telnet handler is a class derived from TelnetHandler and then inherited into the
+ target telnet implementation class:
+
+ \code
+ class MyTelnet
+ : public senf::term::telnethandler::TerminalType,
+ public senf::term::telnethandler::NAWS
+ {
+ MyTelnet(Handle handle) : BaseTelnetProtocol(handle) {}
+
+ // ...
+ };
+ \endcode
+
+ It is very important, the BaseTelnetProtocol is \e always inherited by \c public \c virtual
+ inheritance. This allows the BaseTelnetProtocol constructor to be called by the most derived
+ class directly as above.
+
+ Each terminal handler may provide an additional API and/or additional virtual function
+ callbacks.
+
+ To implement a new terminal handler, derive from TelnetHandler and register the
+ handler. BaseTelnetProtocol will automatically request the corresponding option to be
+ enabled and will call the handlers \c v_init() member as soon as the peer as asserted the
+ option.
+
+ Whenever a subnegotiation for the registered handler is received, the handlers
+ \c v_handleOptionParameters() member is called.
+
+ \code
+ class MyTelnetHandler
+ : public senf::term::BaseTelnetProtocol::TelnetHandler
+ {
+ public:
+ // This constant is MANDATORY and gives the option code which this handler services
+ static option_type const OPTION_CODE = MY_OPTION_CODE;
+
+ void frobble() { // ... }
+
+ protected:
+ MyTelnetHandler() { registerHandler(this); }
+
+ private:
+ virtual void v_init()
+ {
+ sendOptionParameters(OPTION_CODE, "my special subnegotiation");
+ incrementRequestCounter();
+ }
+
+ virtual void v_handleOptionParameters(std::string const & data)
+ {
+ if (data == "another special subnegotiation")
+ decrementRequestCounter();
+ }
+ };
+ \endcode
\todo SYNCH handling
+
+ \ingroup telnet_group
*/
class BaseTelnetProtocol
{
ConnectedCommunicationPolicy,
StreamFramingPolicy,
ReadablePolicy,
- WriteablePolicy>::policy> Handle;
+ WriteablePolicy>::policy> Handle; ///< Type of socket handle required
- typedef unsigned char option_type;
+ typedef unsigned char option_type; ///< Type of telnet option numbers
struct TelnetHandler;
- void write(std::string const & s);
- void write(char c);
-
- Handle handle();
-
- void sendNOP();
- void sendBRK();
- void sendIP();
- void sendAO();
- void sendAYT();
- void sendEC();
- void sendEL();
- void sendGA();
+ void write(std::string const & s); ///< Send string to peer
+ /**< The string will be correctly quoted and newline chars
+ will be sent as CR/LF pairs. */
+ void write(char c); ///< Send single character to peer
+ /**< The character will be correctly quoted and newline
+ chars will be sent as CR/LF pairs. */
+
+ Handle handle(); ///< Get socket handle
+
+ void sendNOP(); ///< Send NOP to peer
+ void sendBRK(); ///< Send BReaK to peer
+ void sendIP(); ///< Send InterruptProcess to peer
+ void sendAO(); ///< Send AbortOutput to peer
+ void sendAYT(); ///< Send AreYouThere to peer
+ void sendEC(); ///< Send EraseCharacter to peer
+ void sendEL(); ///< Send EraseLine to peer
+ void sendGA(); ///< Send GoAhead to peer
void sendOptionParameters(option_type option, std::string const & data);
+ ///< Send extended option parameter to peer
+ /**< This will send \a data as extended option parameter of
+ option \a option to peer via a subnegotiation. */
void requestLocalOption(option_type option, bool enabled = true);
+ ///< Request option to be enabled here
+ /**< This will send a WILL \a option request to the peer */
void acceptLocalOption(option_type option, bool enabled = true);
+ ///< Accept a request for an option to be enabled here
+ /**< If the peer sends a DO \a option request, the request
+ will be granted */
void requestPeerOption(option_type option, bool enabled = true);
+ ///< Request peer to enable an option
+ /**< This will send a DO \a option request to the peer */
void acceptPeerOption(option_type option, bool enabled = true);
+ ///< Accept a request by the peer to enable an option
+ /**< If the peer sends a WILL \a option request, the request
+ will be ganted */
- bool localOption(option_type option);
- bool peerOption(option_type option);
+ bool localOption(option_type option); ///< \c true, if \a option locally enabled
+ bool peerOption(option_type option); ///< \c true, if \a option enabled in peer
protected:
- explicit BaseTelnetProtocol(Handle handle);
- BaseTelnetProtocol();
+ explicit BaseTelnetProtocol(Handle handle); ///< Construct telnet protocol handler
+ BaseTelnetProtocol(); ///< Provided for TelnetHandler mixins only
+
virtual ~BaseTelnetProtocol();
template <class Handler>
void registerHandler(Handler * h, bool request=true);
+ ///< Register a TelnetHandler
- void incrementRequestCounter();
- void decrementRequestCounter();
- bool requestsPending();
+ void incrementRequestCounter(); ///< Increment request counter
+ /**< This member may be called by a telnet handler to wait
+ for additional negotiations. It must be paired with a
+ corresponding decrementRequestCounter() call when that
+ negotiation is received. */
+ void decrementRequestCounter(); ///< Decrement request counter
+ /**< \see inrementRequestCounter() */
+ bool requestsPending(); ///< \c true, if there are pending requests
#ifndef DOXYGEN
private:
#endif
- virtual void v_setupComplete() = 0;
- virtual void v_charReceived(char c) = 0;
- virtual void v_eof() = 0;
-
- virtual void v_handleNOP();
- virtual void v_handleBRK();
- virtual void v_handleIP();
- virtual void v_handleAO();
- virtual void v_handleAYT();
- virtual void v_handleEC();
- virtual void v_handleEL();
- virtual void v_handleGA();
+ virtual void v_setupComplete() = 0; ///< Called, when no further requests are pending
+ /**< This callback will be called, when no further
+ negotiations are to be expected. The default
+ negotiation timeout is 500ms. If no reply is received
+ in this time, the request is abandoned and
+ v_setupComplete() is called.
+
+ mixin TelnetHandler's may additionally increment the
+ request counter to wait for specific
+ subnegotiations. v_setupComplete() will be called, when
+ all these negotiations are complete or have timed
+ out. */
+ virtual void v_charReceived(char c) = 0; ///< Called whenever a data character is received
+ virtual void v_eof() = 0; ///< Called on input EOF
+
+ virtual void v_handleNOP(); ///< Called, when the peer sends a NOP
+ virtual void v_handleBRK(); ///< Called, when the peer sends a BReaK
+ virtual void v_handleIP(); ///< Called, when the peer sends an InterruptProcess
+ virtual void v_handleAO(); ///< Called, when the peer sends an AbortOutput
+ virtual void v_handleAYT(); ///< Called, when the peer sends an AreYouThere
+ virtual void v_handleEC(); ///< Called, when the peer sends an EraseCharacter
+ virtual void v_handleEL(); ///< Called, when the peer sends an EraseLine
+ virtual void v_handleGA(); ///< Called, when the peer sends a GoAhead
-#ifdef DOXYGEN
private:
-#endif
void handleChar(char c);
void handleNormalChar(char c);
void handleCommand(char c);
friend class TelnetHandler;
};
+ /** \brief Telnet handler base class
+
+ \see BaseTelnetProtocol
+ */
struct BaseTelnetProtocol::TelnetHandler
: public virtual BaseTelnetProtocol
{
virtual ~TelnetHandler();
- virtual void v_init() = 0;
+ virtual void v_init() = 0; ///< Called, after option has been enabled
virtual void v_handleOptionParameters(std::string const & data) = 0;
+ ///< Called, whenever a subnegotiation is received
};
- // See http://www.iana.org/assignments/telnet-options for a list of options
+ /** \brief Telnet option codes
+
+ See http://www.iana.org/assignments/telnet-options for a list of options
+
+ \ingroup telnet_group
+ */
namespace telnetopt { BaseTelnetProtocol::option_type const ECHO = 1u; }
namespace telnetopt { BaseTelnetProtocol::option_type const TRANSMIT_BINARY = 0u; }
namespace telnetopt { BaseTelnetProtocol::option_type const SUPPRESS_GO_AHEAD = 3u; }
namespace telnetopt { BaseTelnetProtocol::option_type const NAWS = 31u; }
namespace telnetopt { BaseTelnetProtocol::option_type const LINEMODE = 34u; }
+/** \brief Telnet handlers
+
+ \ingroup telnet_group */
namespace telnethandler {
+ /** \brief Implement TERMINAL_TYPE option
+
+ This telnet handler implements the TERMINAL_TYPE option. The handler automatically requests
+ the first terminal type during initialization. Further terminal types may then be reqeusted
+ by calling nextTerminalType().
+
+ The last received terminal type will be returned by the terminalType() member.
+
+ This implementation only provides server support (querying the terminal type).
+
+ \see BaseTelnetProtocol for how to integrate this handler \n
+ <a href="http://tools.ietf.org/html/rfc1091">RFC 1091</a> Telnet Terminal-Type Option
+ */
class TerminalType
: public BaseTelnetProtocol::TelnetHandler
{
public:
static option_type const OPTION_CODE = telnetopt::TERMINAL_TYPE;
- void nextTerminalType();
- std::string const & terminalType() const;
+ void nextTerminalType(); ///< Request another terminal type
+ std::string const & terminalType() const; ///< Return current terminal type
protected:
TerminalType();
std::string type_;
};
+ /** \brief Implement NAWS (Negotiation About Window Size) option
+
+ This telnet handler implements the NAWS option. The client terminals window size will be
+ requested during initialization. The current window size may always be accessed using the
+ width() and height() members.
+
+ Whenever the window size is changed, the v_windowSizeChanged() function is called. This
+ function must be implemented in a derived class.
+
+ \see BaseTelnetProtocol for how to integrate this handler \n
+ <a href="http://tools.ietf.org/html/rfc1073">RFC 1073</a> Telnet Window Size Option
+ */
class NAWS
: public BaseTelnetProtocol::TelnetHandler
{
public:
static option_type const OPTION_CODE = telnetopt::NAWS;
- unsigned width() const;
- unsigned height() const;
+ unsigned width() const; ///< Get current client window width
+ unsigned height() const; ///< Get current client window height
protected:
NAWS();
+# ifndef DOXYGEN
private:
- virtual void v_windowSizeChanged() = 0;
+# endif
+ virtual void v_windowSizeChanged() = 0; ///< Called, whenever window size changes
+ /**< This member is called for every window size change \e
+ after initialization. */
+ private:
virtual void v_init();
virtual void v_handleOptionParameters(std::string const & data);
namespace senf {
namespace term {
+ /** \brief AbstractTerminal interface implementation based on telnet
+
+ This class provides a telnet server implementation implementing the AbstractTerminal
+ interface.
+
+ TelnetTerminal provides one additional callback which needs to be implemented in a derived
+ class: v_setupFailed(). This member will be called, when not all required telnet options are
+ supported by the telnet client. In this case, the communication will be switched back into
+ line-oriented mode and v_setupFailed() is called.
+
+ \ingroup telnet_group
+ */
class TelnetTerminal
: public telnethandler::TerminalType,
public telnethandler::NAWS,
public:
TelnetTerminal();
+ ///\name AbstractTerminal interface implementation
+ ///\{
virtual void setCallbacks(AbstractTerminal::Callbacks & cb);
virtual std::string terminalType();
virtual unsigned width();
virtual unsigned height();
virtual void write(char ch);
+ ///\}
+ protected:
+
+# ifndef DOXYGEN
private:
- virtual void v_setupFailed() = 0;
+# endif
+ virtual void v_setupFailed() = 0; ///< Called when the telnet setup has failed
+ private:
virtual void v_setupComplete();
virtual void v_charReceived(char ch);
virtual void v_windowSizeChanged();
namespace senf {
namespace term {
+ /** \defgroup terminfo_group Terminfo
+
+ This facility provides access to the terminfo database. It partially re-implements the
+ terminfo suppoprt in \c libncurses.
+
+ \li The senf::term::Terminfo class provides basic terminfo property access and supports terminfo string
+ formatting
+ \li The senf::term::KeyParser class uses the properties found in a Terminfo instance to
+ parser keyboard escape sequences into key codes
+
+ The terminfo implementation is based on the \c utio library by Mike Sharov
+ <msharov@users.sourceforge.net> found at http://sourceforge.net/projects/utio.
+ */
+
+ /** \brief Terminfo database entry
+
+ This class reads a single terminfo database entry and allows to access the terminfo
+ properties.
+
+ \ingroup terminfo_group
+ */
class Terminfo
{
public:
///////////////////////////////////////////////////////////////////////////
// Types
+ /** \brief NoValue constant
+ This value represents the absence of a numeric property value */
enum { NoValue = -1 };
+ /** \brief Terminfo property constants
+
+ This class provides a namespace for all Terminfo property constants
+ */
struct properties
{
+ /** \brief Boolean terminfo properties */
enum Boolean {
AutoLeftMargin, AutoRightMargin, NoEscCtlc, CeolStandoutGlitch, EatNewlineGlitch,
EraseOverstrike, GenericType, HardCopy, HasMetaKey, HasStatusLine, InsertNullGlitch,
NoCorrectlyWorkingCr, GnuHasMetaKey, LinefeedIsNewline, HasHardwareTabs,
ReturnDoesClrEol };
+ /** \brief Boolean property names
+ \hideinitializer */
static char const * const BooleanNames[];
-
+
+ /** \brief Numeric terminfo properties */
enum Numeric {
Columns, InitTabs, Lines, LinesOfMemory, MagicCookieGlitch, PaddingBaudRate,
VirtualTerminal, WidthStatusLine, NumLabels, LabelHeight, LabelWidth, MaxAttributes,
MagicCookieGlitchUl, CarriageReturnDelay, NewLineDelay, BackspaceDelay,
HorizontalTabDelay, NumberOfFunctionKeys };
+ /** \brief Numeric property names
+ \hideinitializer */
static char const * const NumericNames[];
-
+
+ /** \brief String terminfo properties */
enum String {
BackTab, Bell, CarriageReturn, ChangeScrollRegion, ClearAllTabs, ClearScreen,
ClrEol, ClrEos, ColumnAddress, CommandCharacter, CursorAddress, CursorDown,
AcsLlcorner, AcsUrcorner, AcsLrcorner, AcsLtee, AcsRtee, AcsBtee, AcsTtee, AcsHline,
AcsVline, AcsPlus, MemoryLock, MemoryUnlock, BoxChars1 };
+ /** \brief String property names
+ \hideinitializer */
static char const * const StringNames[];
};
- typedef boost::int16_t number_t;
- typedef char const* string_t;
+ typedef boost::int16_t number_t; ///< Numeric terminfo property type
+ typedef char const* string_t; ///< String terminfo property type
///////////////////////////////////////////////////////////////////////////
Terminfo();
- explicit Terminfo(std::string const & term);
- void load(std::string const & term);
+ explicit Terminfo(std::string const & term); ///< Load terminfo entry \a term
+ void load(std::string const & term); ///< Load terminfo entry \a term
- bool getFlag(properties::Boolean p) const;
- number_t getNumber(properties::Numeric p) const;
- string_t getString(properties::String p) const;
- bool hasProperty(properties::Boolean p) const;
- bool hasProperty(properties::Numeric p ) const;
- bool hasProperty(properties::String p ) const;
+ bool getFlag(properties::Boolean p) const; ///< Get boolean property value
+ number_t getNumber(properties::Numeric p) const; ///< Get numeric property value
+ string_t getString(properties::String p) const; ///< Get string property value
+ /**< If the property does not exist, 0 is returned */
+ bool hasProperty(properties::Boolean p) const; ///< \c true, if boolean property \a p exists
+ bool hasProperty(properties::Numeric p ) const; ///< \c true, if numeric property \a p exists
+ bool hasProperty(properties::String p ) const; ///< \c true, if string property \a p exists
+
std::string formatString(properties::String p,
number_t arg1=NoValue, number_t arg2=NoValue,
number_t arg3=NoValue, number_t arg4=NoValue,
number_t arg5=NoValue, number_t arg6=NoValue,
number_t arg7=NoValue, number_t arg8=NoValue,
number_t arg9=NoValue) const;
+ ///< Format string property value
+ /**< Formats the string property \a p containing special
+ terminfo codes. Terminfo supports up to 9 parameters. */
///////////////////////////////////////////////////////////////////////////
- void dump(std::ostream & os) const;
+ void dump(std::ostream & os) const; ///< Dump a description of the terminfo entry
+ /** \brief Invalid, incomplete or non-existent terminfo entry exception */
struct InvalidTerminfoException : public senf::Exception
{ InvalidTerminfoException() : senf::Exception("Unreadable terminfo file") {} };
StringPool stringPool_;
};
+ /** \brief Parse key escape sequences
+ The KeyParser will read the relevant properties from a terminfo entry and then provides
+ functions to parser keyboard escape sequences.
+
+ All keys are returned as keyboard code's. Values 0 to 255 represent ordinary ASCII
+ characters, larger values are special keys taken from the KeyCode \c enum
+
+ \ingroup terminfo_group
+ */
class KeyParser
{
public:
///////////////////////////////////////////////////////////////////////////
// Types
+ /** \brief Special keyboard key codes */
enum KeyCode {
Space = ' ', Tab = '\t', Return = '\r', First = 0xE000, Esc = First, Backspace, Backtab,
Begin, CATab, CTab, Cancel, Center, Clear, ClearToEOL, ClearToEOS, Close, Command, Copy,
ShiftRedo, ShiftReplace, ShiftResume, ShiftRight, ShiftSave, ShiftSuspend, ShiftTab,
ShiftUndo, Suspend, Undo, Up, UpLeft, UpRight, Incomplete = 0xE0FF };
+ /** \brief Special key code names
+ \hideinitializer */
static char const * const KeyNames[];
- typedef wchar_t keycode_t;
- typedef std::string::size_type size_type;
+ typedef wchar_t keycode_t; ///< Key code data type
+ typedef std::string::size_type size_type; ///< String length type
+ /** \brief Helper to convert uppercase char to Control key code */
static keycode_t Ctrl(char ch) { return ch-'@'; }
///////////////////////////////////////////////////////////////////////////
KeyParser();
- explicit KeyParser(Terminfo const & ti);
- void load(Terminfo const & ti);
+ explicit KeyParser(Terminfo const & ti); ///< Load keymap information from \a ti
+ void load(Terminfo const & ti); ///< Load keymap information from \a ti
std::pair<keycode_t, size_type> lookup(std::string const & key) const;
- static std::string describe(keycode_t key);
-
- void dump(std::ostream & os) const;
+ ///< Lookup up string \a key
+ /**< This call will look up the string in \a key in the
+ keymap. The return value is a pair.
+ \li the first value is the key code
+ \li the second value is the number of characters in \a
+ key which have been interpreted and returned in the
+ first value
+
+ If \a key is not a complete key sequence, the return
+ key code will be the \c Invalid value and the returned
+ escape sequence size will be 0.
+
+ If \a key does not start with an escape sequence, the
+ returned key code will be the first character from \a
+ key and the escape sequence size will be 1.
+
+ Otherwise \a key starts with a complete escape
+ sequence. The returned key code will be a value from
+ the KeyCode enum and the escape sequence size will be
+ returned accordingly. */
+ static std::string describe(keycode_t key); ///< Return descriptive, printable key name
+
+ void dump(std::ostream & os) const; ///< Dump keymap for debug purposes
private:
typedef std::map<std::string, KeyCode> Keytable;