vte: implement local echo mode
authorDavid Herrmann <dh.herrmann@googlemail.com>
Wed, 30 May 2012 15:44:12 +0000 (17:44 +0200)
committerDavid Herrmann <dh.herrmann@googlemail.com>
Wed, 30 May 2012 15:44:12 +0000 (17:44 +0200)
If SEND_RECEIVE_MODE is not set, we have to echo all data we send out.
That is, all escape sequences and all characters are directly interpreted
by us. To avoid recursion, we use a simply protection. However, some
escape sequences don't make sense in echo mode but we don't care here, as
this is a problem of the application/client, not us.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
src/vte.c

index 9e8fb2c..13d80c7 100644 (file)
--- a/src/vte.c
+++ b/src/vte.c
@@ -126,7 +126,7 @@ enum parser_action {
 #define FLAG_USE_C1                            0x00000020 /* Explicitely use 8bit C1 codes; TODO: implement */
 #define FLAG_KEYBOARD_ACTION_MODE              0x00000040 /* Disable keyboard; TODO: implement? */
 #define FLAG_INSERT_REPLACE_MODE               0x00000080 /* Enable insert mode */
-#define FLAG_SEND_RECEIVE_MODE                 0x00000100 /* Disable local echo; TODO: implement */
+#define FLAG_SEND_RECEIVE_MODE                 0x00000100 /* Disable local echo */
 #define FLAG_TEXT_CURSOR_MODE                  0x00000200 /* Show cursor; TODO: implement */
 #define FLAG_INVERSE_SCREEN_MODE               0x00000400 /* Inverse colors; TODO: implement */
 #define FLAG_ORIGIN_MODE                       0x00000800 /* Relative origin for cursor; TODO: implement */
@@ -141,6 +141,7 @@ struct kmscon_vte {
        void *data;
 
        struct kmscon_utf8_mach *mach;
+       unsigned long parse_cnt;
 
        unsigned int state;
        unsigned int csi_argc;
@@ -235,6 +236,19 @@ void kmscon_vte_unref(struct kmscon_vte *vte)
  * As a rule of thumb do never send 8bit characters in escape sequences and also
  * avoid all 8bit escape codes including the C1 codes. This will guarantee that
  * all kind of clients are always compatible to us.
+ *
+ * If SEND_RECEIVE_MODE is off (that is, local echo is on) we have to send all
+ * data directly to ourself again. However, we must avoid recursion when
+ * kmscon_vte_input() itself calls vte_write*(), therefore, we increase the
+ * PARSER counter when entering kmscon_vte_input() and reset it when leaving it
+ * so we never echo data that origins from kmscon_vte_input().
+ * But note that SEND_RECEIVE_MODE is inherently broken for escape sequences
+ * that request answers. That is, if we send a request to the client that awaits
+ * a response and parse that request via local echo ourself, then we will also
+ * send a response to the client even though he didn't request one. This
+ * recursion fix does not avoid this but only prevents us from endless loops
+ * here. Anyway, only few applications rely on local echo so we can safely
+ * ignore this.
  */
 static void vte_write_debug(struct kmscon_vte *vte, const char *u8, size_t len,
                            bool raw, const char *file, int line)
@@ -253,6 +267,10 @@ static void vte_write_debug(struct kmscon_vte *vte, const char *u8, size_t len,
        }
 #endif
 
+       /* in local echo mode, directly parse the data again */
+       if (!vte->parse_cnt && !(vte->flags & FLAG_SEND_RECEIVE_MODE))
+               kmscon_vte_input(vte, u8, len);
+
        vte->write_cb(vte, u8, len, vte->data);
 }
 
@@ -1476,6 +1494,7 @@ void kmscon_vte_input(struct kmscon_vte *vte, const char *u8, size_t len)
        if (!vte || !vte->con)
                return;
 
+       ++vte->parse_cnt;
        for (i = 0; i < len; ++i) {
                if (vte->flags & FLAG_7BIT_MODE) {
                        if (u8[i] & 0x80)
@@ -1493,6 +1512,7 @@ void kmscon_vte_input(struct kmscon_vte *vte, const char *u8, size_t len)
                        }
                }
        }
+       --vte->parse_cnt;
 }
 
 void kmscon_vte_handle_keyboard(struct kmscon_vte *vte,