Utils/Termlib: Fix handling of very narrow windows
g0dil [Wed, 7 Jan 2009 15:23:31 +0000 (15:23 +0000)]
Utils/Termlib: Implement terminal setup failure handling

git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@1044 270642c3-0616-0410-b53a-bc976706d245

Utils/Termlib/AbstractTerminal.hh
Utils/Termlib/Editor.cc
Utils/Termlib/Editor.hh
Utils/Termlib/Telnet.cci
Utils/Termlib/Telnet.hh
Utils/Termlib/TelnetTerminal.cc
Utils/Termlib/TelnetTerminal.hh
Utils/Termlib/Terminfo.cc
Utils/Termlib/telnetServer.cc
project.el

index 01d72f7..f38a4b5 100644 (file)
@@ -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;
         };
index 0023322..57e1e78 100644 (file)
@@ -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())
index de94ae1..e5cb475 100644 (file)
@@ -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);
 
index ed7d902..9804e99 100644 (file)
@@ -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);
index c50f87b..4cc6af4 100644 (file)
@@ -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);
index 6b28a4f..5e08938 100644 (file)
@@ -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)
index 98cab31..ed2be42 100644 (file)
@@ -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_;
     };
 
 }}
index 232a188..603676c 100644 (file)
@@ -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;
index 4f9ccf2..3c5c9fd 100644 (file)
@@ -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()
index f34d538..74eafad 100644 (file)
@@ -4,6 +4,7 @@
   (save-excursion
     (back-to-indentation)
     (if (and (looking-at "namespace")
+            (looking-at ".*{")
             (not (looking-at ".*}")))
        [0] '+)))