Robert de Bath's multi-purpose patch, slightly modified.
[u/mdw/putty] / telnet.c
index 20341cd..24962bb 100644 (file)
--- a/telnet.c
+++ b/telnet.c
@@ -174,6 +174,9 @@ static void c_write (char *buf, int len) {
        if (new_head != inbuf_reap) {
            inbuf[inbuf_head] = *buf++;
            inbuf_head = new_head;
+       } else {
+            term_out();
+            if( inbuf_head == inbuf_reap ) len++; else break;
        }
     }
 }
@@ -184,7 +187,7 @@ static void log_option (char *sender, int cmd, int option) {
            (cmd == WILL ? "WILL" : cmd == WONT ? "WONT" :
             cmd == DO ? "DO" : cmd == DONT ? "DONT" : "<??>"),
            telopt(option));
-    lognegot(buf);
+    logevent(buf);
 }
 
 static void send_opt (int cmd, int option) {
@@ -285,11 +288,11 @@ static void process_subneg (void) {
            n = 4 + strlen(cfg.termspeed);
            b[n] = IAC; b[n+1] = SE;
            s_write (b, n+2);
-           lognegot("server:\tSB TSPEED SEND");
+           logevent("server:\tSB TSPEED SEND");
            sprintf(logbuf, "client:\tSB TSPEED IS %s", cfg.termspeed);
-           lognegot (logbuf);
+           logevent (logbuf);
        } else
-           lognegot ("server:\tSB TSPEED <something weird>");
+           logevent ("server:\tSB TSPEED <something weird>");
        break;
       case TELOPT_TTYPE:
        if (sb_len == 1 && sb_buf[0] == TELQUAL_SEND) {
@@ -302,11 +305,11 @@ static void process_subneg (void) {
            b[n+4] = IAC; b[n+5] = SE;
            s_write (b, n+6);
            b[n+4] = 0;
-           lognegot("server:\tSB TTYPE SEND");
+           logevent("server:\tSB TTYPE SEND");
            sprintf(logbuf, "client:\tSB TTYPE IS %s", b+4);
-           lognegot(logbuf);
+           logevent(logbuf);
        } else
-           lognegot("server:\tSB TTYPE <something weird>\r\n");
+           logevent("server:\tSB TTYPE <something weird>\r\n");
        break;
       case TELOPT_OLD_ENVIRON:
       case TELOPT_NEW_ENVIRON: 
@@ -316,7 +319,7 @@ static void process_subneg (void) {
            char logbuf[50];
            p++;
            sprintf (logbuf, "server:\tSB %s SEND", telopt(sb_opt));
-           lognegot (logbuf);
+           logevent (logbuf);
            if (sb_opt == TELOPT_OLD_ENVIRON) {
                if (cfg.rfc_environ) {
                    value = RFC_VALUE;
@@ -368,7 +371,7 @@ static void process_subneg (void) {
            s_write (b, n);
            sprintf(logbuf, "client:\tSB %s IS %s", telopt(sb_opt),
                    n==6 ? "<nothing>" : "<stuff>");
-           lognegot (logbuf);
+           logevent (logbuf);
        }
        break;
     }
@@ -411,9 +414,11 @@ static void do_telnet_read (char *buf, int len) {
            else if (c == WONT) telnet_state = SEENWONT;
            else if (c == SB) telnet_state = SEENSB;
            else {
-               /* ignore (and print) everything else */
-               b[0] = c;
-               c_write(b,1);
+               /* ignore everything else; print it if it's IAC */
+               if (c == IAC) {
+                   b[0] = c;
+                   c_write(b,1);
+               }
                telnet_state = TOPLEVEL;
            }
            break;
@@ -586,14 +591,22 @@ static int telnet_msg (WPARAM wParam, LPARAM lParam) {
     int ret;
     char buf[256];
 
-    if (s == INVALID_SOCKET)          /* how the hell did we get here?! */
-       return -5000;
+    /*
+     * Because reading less than the whole of the available pending
+     * data can generate an FD_READ event, we need to allow for the
+     * possibility that FD_READ may arrive with FD_CLOSE already in
+     * the queue; so it's possible that we can get here even with s
+     * invalid. If so, we return 1 and don't worry about it.
+     */
+    if (s == INVALID_SOCKET)
+       return 1;
 
     if (WSAGETSELECTERROR(lParam) != 0)
        return -WSAGETSELECTERROR(lParam);
 
     switch (WSAGETSELECTEVENT(lParam)) {
       case FD_READ:
+      case FD_CLOSE:
        ret = recv(s, buf, sizeof(buf), 0);
        if (ret < 0 && WSAGetLastError() == WSAEWOULDBLOCK)
            return 1;
@@ -601,7 +614,7 @@ static int telnet_msg (WPARAM wParam, LPARAM lParam) {
            return -10000-WSAGetLastError();
        if (ret == 0) {
            s = INVALID_SOCKET;
-           return 0;                  /* can't happen, in theory */
+           return 0;
        }
 #if 0
        if (in_synch) {
@@ -632,9 +645,6 @@ static int telnet_msg (WPARAM wParam, LPARAM lParam) {
        if (outbuf_head != outbuf_reap)
            try_write();
        return 1;
-      case FD_CLOSE:
-       s = INVALID_SOCKET;
-       return 0;
     }
     return 1;                         /* shouldn't happen, but WTF */
 }
@@ -681,7 +691,7 @@ static void telnet_size(void) {
     sprintf(logbuf, "client:\tSB NAWS %d,%d",
            ((unsigned char)b[3] << 8) + (unsigned char)b[4],
            ((unsigned char)b[5] << 8) + (unsigned char)b[6]);
-    lognegot (logbuf);
+    logevent (logbuf);
 }
 
 /*