{
struct Callbacks {
virtual ~Callbacks() {}
- virtual void cb_init() = 0;
+ virtual bool cb_init() = 0;
virtual void cb_charReceived(char ch) = 0;
virtual void cb_windowSizeChanged() = 0;
};
return column_;
}
-prefix_ void senf::term::BaseEditor::cb_init()
+prefix_ bool senf::term::BaseEditor::cb_init()
{
- tifo_.load(terminal_->terminalType());
- keyParser_.load(tifo_);
+ try {
+ tifo_.load(terminal_->terminalType());
+ keyParser_.load(tifo_);
+ }
+ catch (Terminfo::InvalidTerminfoException & ex) {
+ return false;
+ }
typedef Terminfo::properties p;
if (! (tifo_.hasProperty(p::ClrEol) &&
(tifo_.hasProperty(p::ParmRightCursor) || tifo_.hasProperty(p::CursorRight)) &&
(tifo_.hasProperty(p::ParmLeftCursor) || tifo_.hasProperty(p::CursorLeft))))
- throw Terminfo::InvalidTerminfoException();
+ return false;
if (tifo_.hasProperty(Terminfo::properties::KeypadXmit))
write(tifo_.getString(Terminfo::properties::KeypadXmit));
{
prompt_ = text;
promptWidth_ = prompt_.size();
+ if (promptWidth_ > width() - 4 && width() > 4)
+ promptWidth_ = width() - 4;
editWidth_ = width() - promptWidth_ - 3;
if (enabled_)
redisplay();
return;
clearLine();
setBold();
- put(prompt_);
+ if (prompt_.size() > promptWidth_)
+ put(prompt_.substr(prompt_.size()-promptWidth_));
+ else
+ put(prompt_);
put( displayPos_ > 0 ? '<' : ' ' );
if (text_.size() > displayPos_ + editWidth_) {
toColumn(editWidth_ + promptWidth_ + 1);
bindings_.erase(key);
}
-prefix_ void senf::term::LineEditor::cb_init()
+prefix_ bool senf::term::LineEditor::cb_init()
{
- BaseEditor::cb_init();
- editWidth_ = width() - promptWidth_ - 3;
+ if (!BaseEditor::cb_init())
+ return false;
+ prompt(prompt_);
forceRedisplay();
+ return true;
}
prefix_ void senf::term::LineEditor::cb_windowSizeChanged()
{
BaseEditor::cb_windowSizeChanged();
- editWidth_ = width() - promptWidth_ - 3;
+ prompt(prompt_);
gotoChar(point_);
forceRedisplay();
}
prefix_ void senf::term::LineEditor::v_keyReceived(keycode_t key)
{
+ if (! enabled_)
+ return;
lastKey_ = key;
KeyMap::iterator i (bindings_.find(key));
if (i != bindings_.end())
unsigned width();
protected:
- virtual void cb_init();
+ virtual bool cb_init();
virtual void cb_windowSizeChanged();
private:
void unsetKey(keycode_t key);
private:
- virtual void cb_init();
+ virtual bool cb_init();
virtual void cb_windowSizeChanged();
virtual void v_keyReceived(keycode_t key);
prefix_ senf::term::BaseTelnetProtocol::~BaseTelnetProtocol()
{}
+prefix_ senf::term::BaseTelnetProtocol::Handle senf::term::BaseTelnetProtocol::handle()
+{
+ return handle_;
+}
+
prefix_ void senf::term::BaseTelnetProtocol::incrementRequestCounter()
{
++ pendingRequests_;
getOption(false, option).wantState = OptInfo::ACCEPTED;
}
+prefix_ bool senf::term::BaseTelnetProtocol::localOption(option_type option)
+{
+ return getOption(true, option).enabled;
+}
+
+prefix_ bool senf::term::BaseTelnetProtocol::peerOption(option_type option)
+{
+ return getOption(false, option).enabled;
+}
+
prefix_ void senf::term::BaseTelnetProtocol::emit(char c)
{
v_charReceived(c);
void write(std::string const & s);
void write(char c);
+ Handle handle();
+
void sendNOP();
void sendBRK();
void sendIP();
void requestPeerOption(option_type option, bool enabled = true);
void acceptPeerOption(option_type option, bool enabled = true);
+
+ bool localOption(option_type option);
+ bool peerOption(option_type option);
protected:
explicit BaseTelnetProtocol(Handle handle);
///////////////////////////////cc.p////////////////////////////////////////
prefix_ senf::term::TelnetTerminal::TelnetTerminal()
+ : setupFailed_ (false)
{
requestPeerOption(telnetopt::SUPPRESS_GO_AHEAD);
requestLocalOption(telnetopt::SUPPRESS_GO_AHEAD);
prefix_ void senf::term::TelnetTerminal::v_setupComplete()
{
- callbacks_->cb_init();
+ if (setupFailed_)
+ v_setupFailed();
+ else if (! (width() > 0
+ && ! terminalType().empty()
+ && localOption(telnetopt::SUPPRESS_GO_AHEAD)
+ && peerOption(telnetopt::SUPPRESS_GO_AHEAD)
+ && localOption(telnetopt::ECHO)
+ && callbacks_->cb_init())) {
+ setupFailed_ = true;
+ requestPeerOption(telnetopt::SUPPRESS_GO_AHEAD, false);
+ requestLocalOption(telnetopt::SUPPRESS_GO_AHEAD, false);
+ requestLocalOption(telnetopt::ECHO, false);
+ requestPeerOption(telnetopt::TERMINAL_TYPE, false);
+ requestPeerOption(telnetopt::NAWS, false);
+ if (! requestsPending())
+ v_setupFailed();
+ }
}
prefix_ void senf::term::TelnetTerminal::v_charReceived(char ch)
virtual void write(char ch);
private:
+ virtual void v_setupFailed() = 0;
+
virtual void v_setupComplete();
virtual void v_charReceived(char ch);
virtual void v_windowSizeChanged();
AbstractTerminal::Callbacks * callbacks_;
+ bool setupFailed_;
};
}}
strings_.resize(offsets.size());
StringVec::iterator j (strings_.begin());
for (OffsetVec::iterator i (offsets.begin()); i != offsets.end(); ++i, ++j)
- if (*i != NoValue && *i >= 0 && *i < stringPool_.size())
+ if (*i != NoValue && *i >= 0 && unsigned(*i) < stringPool_.size())
*j = &(stringPool_[0]) + *i;
else
*j = 0;
: senf::term::BaseTelnetProtocol (handle),
editor_ (*this, senf::membind(&MyTelnet::executeLine, this))
{
- editor_.prompt("myTelnet$");
+ editor_.prompt("myTelnet-with-an-endlesssly-long-prompt$");
+ editor_.defineKey(senf::term::KeyParser::Ctrl('D'),
+ senf::membind(&MyTelnet::deleteCharOrExit, this));
+ }
+
+ void deleteCharOrExit(senf::term::LineEditor & editor)
+ {
+ if (editor.text().empty()) {
+ exit();
+ }
+ else
+ senf::term::bindings::deleteChar(editor);
+ }
+
+ void exit()
+ {
+ handle().facet<senf::TCPSocketProtocol>().shutdown(senf::TCPSocketProtocol::ShutRD);
+ }
+
+ virtual void v_setupFailed()
+ {
+ SENF_LOG(("Terminal setup failed"));
+ exit();
}
virtual void v_eof()
(save-excursion
(back-to-indentation)
(if (and (looking-at "namespace")
+ (looking-at ".*{")
(not (looking-at ".*}")))
[0] '+)))