From 7554c469e915ecc18a1e45637bf32cbb55b8dbfe Mon Sep 17 00:00:00 2001
From: g0dil <g0dil@wiback.org>
Date: Wed, 7 Jan 2009 15:23:31 +0000
Subject: [PATCH] Utils/Termlib: Fix handling of very narrow windows
 Utils/Termlib: Implement terminal setup failure handling

---
 Utils/Termlib/AbstractTerminal.hh |  2 +-
 Utils/Termlib/Editor.cc           | 32 ++++++++++++++++++++++---------
 Utils/Termlib/Editor.hh           |  4 ++--
 Utils/Termlib/Telnet.cci          | 15 +++++++++++++++
 Utils/Termlib/Telnet.hh           |  5 +++++
 Utils/Termlib/TelnetTerminal.cc   | 19 +++++++++++++++++-
 Utils/Termlib/TelnetTerminal.hh   |  3 +++
 Utils/Termlib/Terminfo.cc         |  2 +-
 Utils/Termlib/telnetServer.cc     | 24 ++++++++++++++++++++++-
 project.el                        |  1 +
 10 files changed, 92 insertions(+), 15 deletions(-)

diff --git a/Utils/Termlib/AbstractTerminal.hh b/Utils/Termlib/AbstractTerminal.hh
index 01d72f712..f38a4b5ba 100644
--- a/Utils/Termlib/AbstractTerminal.hh
+++ b/Utils/Termlib/AbstractTerminal.hh
@@ -39,7 +39,7 @@ namespace term {
     {
         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;
         };
diff --git a/Utils/Termlib/Editor.cc b/Utils/Termlib/Editor.cc
index 002332274..57e1e78ad 100644
--- a/Utils/Termlib/Editor.cc
+++ b/Utils/Termlib/Editor.cc
@@ -130,16 +130,21 @@ prefix_ unsigned senf::term::BaseEditor::currentColumn()
     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));
@@ -220,6 +225,8 @@ prefix_ void senf::term::LineEditor::prompt(std::string const & text)
 {
     prompt_ = text;
     promptWidth_ = prompt_.size();
+    if (promptWidth_ > width() - 4 && width() > 4)
+        promptWidth_ = width() - 4;
     editWidth_ = width() - promptWidth_ - 3;
     if (enabled_)
         redisplay();
@@ -278,7 +285,10 @@ prefix_ void senf::term::LineEditor::forceRedisplay()
         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);
@@ -367,23 +377,27 @@ prefix_ void senf::term::LineEditor::unsetKey(keycode_t key)
     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())
diff --git a/Utils/Termlib/Editor.hh b/Utils/Termlib/Editor.hh
index de94ae135..e5cb475cd 100644
--- a/Utils/Termlib/Editor.hh
+++ b/Utils/Termlib/Editor.hh
@@ -61,7 +61,7 @@ namespace term {
         unsigned width();
 
     protected:
-        virtual void cb_init();
+        virtual bool cb_init();
         virtual void cb_windowSizeChanged();
 
     private:
@@ -131,7 +131,7 @@ namespace term {
         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);
 
diff --git a/Utils/Termlib/Telnet.cci b/Utils/Termlib/Telnet.cci
index ed7d90224..9804e995a 100644
--- a/Utils/Termlib/Telnet.cci
+++ b/Utils/Termlib/Telnet.cci
@@ -74,6 +74,11 @@ prefix_ unsigned senf::term::telnethandler::NAWS::height()
 prefix_ senf::term::BaseTelnetProtocol::~BaseTelnetProtocol()
 {}
 
+prefix_ senf::term::BaseTelnetProtocol::Handle senf::term::BaseTelnetProtocol::handle()
+{
+    return handle_;
+}
+
 prefix_ void senf::term::BaseTelnetProtocol::incrementRequestCounter()
 {
     ++ pendingRequests_;
@@ -157,6 +162,16 @@ prefix_ void senf::term::BaseTelnetProtocol::acceptPeerOption(option_type option
     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);
diff --git a/Utils/Termlib/Telnet.hh b/Utils/Termlib/Telnet.hh
index c50f87b4d..4cc6af462 100644
--- a/Utils/Termlib/Telnet.hh
+++ b/Utils/Termlib/Telnet.hh
@@ -65,6 +65,8 @@ namespace term {
         void write(std::string const & s);
         void write(char c);
 
+        Handle handle();
+
         void sendNOP();
         void sendBRK();
         void sendIP();
@@ -81,6 +83,9 @@ namespace term {
 
         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);
diff --git a/Utils/Termlib/TelnetTerminal.cc b/Utils/Termlib/TelnetTerminal.cc
index 6b28a4f46..5e08938e9 100644
--- a/Utils/Termlib/TelnetTerminal.cc
+++ b/Utils/Termlib/TelnetTerminal.cc
@@ -33,6 +33,7 @@
 ///////////////////////////////cc.p////////////////////////////////////////
 
 prefix_ senf::term::TelnetTerminal::TelnetTerminal()
+    : setupFailed_ (false)
 {
     requestPeerOption(telnetopt::SUPPRESS_GO_AHEAD);
     requestLocalOption(telnetopt::SUPPRESS_GO_AHEAD);
@@ -66,7 +67,23 @@ prefix_ void senf::term::TelnetTerminal::write(char ch)
 
 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)
diff --git a/Utils/Termlib/TelnetTerminal.hh b/Utils/Termlib/TelnetTerminal.hh
index 98cab3155..ed2be42d4 100644
--- a/Utils/Termlib/TelnetTerminal.hh
+++ b/Utils/Termlib/TelnetTerminal.hh
@@ -51,11 +51,14 @@ namespace term {
         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_;
     };
 
 }}
diff --git a/Utils/Termlib/Terminfo.cc b/Utils/Termlib/Terminfo.cc
index 232a1886f..603676c86 100644
--- a/Utils/Termlib/Terminfo.cc
+++ b/Utils/Termlib/Terminfo.cc
@@ -450,7 +450,7 @@ prefix_ void senf::term::Terminfo::load(std::istream & is)
     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;
diff --git a/Utils/Termlib/telnetServer.cc b/Utils/Termlib/telnetServer.cc
index 4f9ccf25b..3c5c9fdf2 100644
--- a/Utils/Termlib/telnetServer.cc
+++ b/Utils/Termlib/telnetServer.cc
@@ -49,7 +49,29 @@ namespace {
             : 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()
diff --git a/project.el b/project.el
index f34d53896..74eafadba 100644
--- a/project.el
+++ b/project.el
@@ -4,6 +4,7 @@
   (save-excursion
     (back-to-indentation)
     (if (and (looking-at "namespace")
+	     (looking-at ".*{")
 	     (not (looking-at ".*}")))
 	[0] '+)))
 
-- 
GitLab