Robert de Bath's big patch:
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Mon, 9 Oct 2000 12:53:32 +0000 (12:53 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Mon, 9 Oct 2000 12:53:32 +0000 (12:53 +0000)
  - cope with strange WinSock wrappers not supporting SIOCATMARK
  - define yet more terminal compatibility modes
  - support UK-ASCII (just like US-ASCII but # is a sterling sign)
  - support connection keepalives at a configurable interval

git-svn-id: svn://svn.tartarus.org/sgt/putty@692 cda61777-01e9-0310-a592-d414129be87e

putty.h
settings.c
ssh.c
telnet.c
terminal.c
windlg.c
window.c

diff --git a/putty.h b/putty.h
index 48e9d2e..88437d8 100644 (file)
--- a/putty.h
+++ b/putty.h
@@ -92,7 +92,7 @@ GLOBAL char *logfile;
 
 typedef enum {
     TS_AYT, TS_BRK, TS_SYNCH, TS_EC, TS_EL, TS_GA, TS_NOP, TS_ABORT,
-    TS_AO, TS_IP, TS_SUSP, TS_EOR, TS_EOF, TS_LECHO, TS_RECHO
+    TS_AO, TS_IP, TS_SUSP, TS_EOR, TS_EOF, TS_LECHO, TS_RECHO, TS_PING
 } Telnet_Special;
 
 typedef enum {
@@ -139,6 +139,7 @@ typedef struct {
     enum { PROT_RAW, PROT_TELNET, PROT_SSH } protocol;
     int close_on_exit;
     int warn_on_close;
+    int ping_interval;
     /* SSH options */
     char remote_cmd[512];
     int nopty;
index de1fb26..36db32e 100644 (file)
@@ -48,6 +48,7 @@ void save_settings (char *section, int do_host, Config *cfg) {
     }
     write_setting_i (sesskey, "CloseOnExit", !!cfg->close_on_exit);
     write_setting_i (sesskey, "WarnOnClose", !!cfg->warn_on_close);
+    write_setting_i (sesskey, "PingInterval", cfg->ping_interval);
     write_setting_s (sesskey, "TerminalType", cfg->termtype);
     write_setting_s (sesskey, "TerminalSpeed", cfg->termspeed);
     {
@@ -157,6 +158,7 @@ void load_settings (char *section, int do_host, Config *cfg) {
 
     gppi (sesskey, "CloseOnExit", 1, &cfg->close_on_exit);
     gppi (sesskey, "WarnOnClose", 1, &cfg->warn_on_close);
+    gppi (sesskey, "PingInterval", 0, &cfg->ping_interval);
     gpps (sesskey, "TerminalType", "xterm", cfg->termtype,
          sizeof(cfg->termtype));
     gpps (sesskey, "TerminalSpeed", "38400,38400", cfg->termspeed,
diff --git a/ssh.c b/ssh.c
index f0a26aa..509ea3a 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -2611,6 +2611,14 @@ static void ssh_special (Telnet_Special code) {
             ssh2_pkt_send();
         }
         logevent("Sent EOF message");
+    } else if (code == TS_PING) {
+        if (ssh_version == 1) {
+            send_packet(SSH1_MSG_IGNORE, PKT_STR, "", PKT_END);
+        } else {
+            ssh2_pkt_init(SSH2_MSG_IGNORE);
+            ssh2_pkt_addstring_start();
+            ssh2_pkt_send();
+        }
     } else {
         /* do nothing */
     }
index 4fb39c6..9718348 100644 (file)
--- a/telnet.c
+++ b/telnet.c
@@ -631,8 +631,11 @@ static int telnet_msg (WPARAM wParam, LPARAM lParam) {
       case FD_CLOSE:
        {
            int clear_of_oob = 1;
-           if (ioctlsocket (s, SIOCATMARK, &clear_of_oob) < 0 )
-               return -20000-WSAGetLastError();
+
+           /* Don't check for error return; some shims don't support
+            * this ioctl.
+            */
+           ioctlsocket (s, SIOCATMARK, &clear_of_oob);
 
            in_synch = !clear_of_oob;
 
@@ -747,6 +750,12 @@ static void telnet_special (Telnet_Special code) {
            send_opt (o_echo.nsend, o_echo.option);
        }
        break;
+      case TS_PING: 
+       if (o_they_sga.state == ACTIVE) {
+           b[1] = NOP; 
+           s_write (b, 2); 
+       }
+        break;
     }
 }
 
index e38daa3..8a1d68d 100644 (file)
@@ -25,7 +25,6 @@
 #define CL_ANSI                0x2000  /* ANSI ECMA-48 not in the VT100..VT420 */
 #define CL_OTHER       0x4000  /* Others, Xterm, linux, putty, dunno, etc */
 
-#define TM_ANSIMIN     (CL_ANSIMIN)
 #define TM_VT100       (CL_ANSIMIN|CL_VT100)
 #define TM_VT100AVO    (TM_VT100|CL_VT100AVO)
 #define TM_VT102       (TM_VT100AVO|CL_VT102)
@@ -710,7 +709,7 @@ static void toggle_mode (int mode, int query, int state) {
        repeat_off = !state;
        break;
       case 25:                        /* enable/disable cursor */
-       compatibility(VT220);
+       compatibility2(OTHER,VT220);
        cursor_on = state;
        seen_disp_event = TRUE;
        break;
@@ -734,7 +733,7 @@ static void toggle_mode (int mode, int query, int state) {
         * DONT send TS_RECHO/TS_LECHO; the telnet daemon tries to fix the
         * tty and _really_ confuses some programs.
         */
-       compatibility(VT220);
+       compatibility2(OTHER,VT220);
         ldisc = (state? &ldisc_simple : &ldisc_term);
        break;
       case 20:                        /* Return sends ... */
@@ -903,6 +902,14 @@ static int beep_overload = 0;
                }
                seen_disp_event = TRUE;
                break;
+             case '\177': /* Destructive backspace 
+                             This does nothing on a real VT100 */
+               compatibility(OTHER);
+               if (curs_x && !wrapnext) curs_x--;
+               wrapnext = FALSE;
+               fix_cpos;
+               *cpos = (' ' | curr_attr | ATTR_ASCII);
+               break;
            }
        }
        else switch (termstate) {
@@ -928,12 +935,21 @@ static int beep_overload = 0;
                 * we use the same font as well as the same encoding.
                 */
            case ATTR_LINEDRW:
-               if (c<0x60 || c>0x7F)
+               if (c<0x5f || c>0x7F)
                    *cpos++ = xlat_tty2scr((unsigned char)c) | curr_attr |
                              ATTR_ASCII;
+               else if (c==0x5F)
+                  *cpos++ = ' ' | curr_attr | ATTR_ASCII;
                else
                    *cpos++ = ((unsigned char)c) | curr_attr | ATTR_LINEDRW;
                break;
+           case ATTR_GBCHR:
+               /* If UK-ASCII, make the '#' a LineDraw Pound */
+               if (c == '#') {
+                   *cpos++ = '}' | curr_attr | ATTR_LINEDRW;
+                   break;
+               }
+               /*FALLTHROUGH*/
            default:
                *cpos++ = xlat_tty2scr((unsigned char)c) | curr_attr |
                    (c <= 0x7F ? cset_attr[cset] : ATTR_ASCII);
@@ -1299,16 +1315,16 @@ static int beep_overload = 0;
                          case 7:      /* enable reverse video */
                            curr_attr |= ATTR_REVERSE; break;
                          case 22:     /* disable bold */
-                           compatibility(VT220);
+                           compatibility2(OTHER,VT220);
                            curr_attr &= ~ATTR_BOLD; break;
                          case 24:     /* disable underline */
-                           compatibility(VT220);
+                           compatibility2(OTHER,VT220);
                            curr_attr &= ~ATTR_UNDER; break;
                          case 25:     /* disable blink */
-                           compatibility(VT220);
+                           compatibility2(OTHER,VT220);
                            curr_attr &= ~ATTR_BLINK; break;
                          case 27:     /* disable reverse video */
-                           compatibility(VT220);
+                           compatibility2(OTHER,VT220);
                            curr_attr &= ~ATTR_REVERSE; break;
                          case 30: case 31: case 32: case 33:
                          case 34: case 35: case 36: case 37:
@@ -1424,8 +1440,8 @@ static int beep_overload = 0;
                 * This first appeared in the VT220, but we do need to get 
                 * back to PuTTY mode so I won't check it.
                 *
-                * The arg == 60 is a PuTTY extension.
-                * The 2nd arg, 8bit vs 7bit is not obeyed.
+                * The arg in 40..42 are a PuTTY extension.
+                * The 2nd arg, 8bit vs 7bit is not checked.
                 *
                 * Setting VT102 mode should also change the Fkeys to
                 * generate PF* codes as a real VT102 has no Fkeys.
@@ -1435,9 +1451,47 @@ static int beep_overload = 0;
                 * Note ESC c will NOT change this!
                 */
 
-               if (esc_args[0] == 61)      compatibility_level = TM_VT102;
-               else if (esc_args[0] == 60) compatibility_level = TM_ANSIMIN;
-               else                        compatibility_level = TM_PUTTY;
+               switch (esc_args[0]) {
+               case 61: compatibility_level &= ~TM_VTXXX;
+                        compatibility_level |=  TM_VT102;      break;
+               case 62: compatibility_level &= ~TM_VTXXX;
+                        compatibility_level |=  TM_VT220;      break;
+
+               default: if( esc_args[0] > 60 && esc_args[0] < 70 )
+                           compatibility_level |= TM_VTXXX;    
+                        break;
+
+               case 40: compatibility_level &=  TM_VTXXX;      break;
+               case 41: compatibility_level  =  TM_PUTTY;      break;
+               case 42: compatibility_level  =  TM_SCOANSI;    break;
+
+               case ARG_DEFAULT: 
+                        compatibility_level  =  TM_PUTTY;      break;
+               case 50: break;
+               }
+
+               /* Change the response to CSI c */
+               if (esc_args[0] == 50) {
+                  int i;
+                  char lbuf[64];
+                  strcpy(id_string, "\033[?");
+                  for (i=1; i<esc_nargs; i++) {
+                     if (i!=1) strcat(id_string, ";");
+                     sprintf(lbuf, "%d", esc_args[i]);
+                     strcat(id_string, lbuf);
+                  }
+                  strcat(id_string, "c");
+               }
+
+#if 0
+               /* Is this a good idea ? 
+                * Well we should do a soft reset at this point ...
+                */
+               if (!has_compat(VT420) && has_compat(VT100)) {
+                   if (reset_132) request_resize (132, 24, 1);
+                   else           request_resize ( 80, 24, 1);
+               }
+#endif
                break;
            }
            break;
@@ -1641,10 +1695,10 @@ static int beep_overload = 0;
                ldisc->send ("\033/Z", 3);
                break;
              case '=':
-               app_cursor_keys = TRUE;
+               app_keypad_keys = TRUE;
                break;
              case '>':
-               app_cursor_keys = FALSE;
+               app_keypad_keys = FALSE;
                break;
              case '<':
                /* XXX This should switch to VT100 mode not current or default
@@ -2000,7 +2054,28 @@ void term_mouse (Mouse_Button b, Mouse_Action a, int x, int y) {
                        nl = TRUE;
                }
                while (q < nlpos && q < selend)
-                   *p++ = (unsigned char) (*q++ & CHAR_MASK);
+               {
+                   /* VT Specials -> ISO8859-1  */
+                   static const char poorman2[] =
+ "* # HTFFCRLF\xB0 \xB1 NLVT+ + + + + - - - - - + + + + | <=>=PI!=\xA3 \xB7 ";
+
+                   int ch = (*q & CHAR_MASK);
+
+                   if ((*q & ATTR_LINEDRW) && ch >= 0x60 && ch <  0x7F )
+                   {
+                       int x;
+                       *p++ = poorman2[2*(ch-0x60)];
+                       if ( (x = poorman2[2*(ch-0x60)+1]) != ' ')
+                           *p++ = x;
+                   }
+#if 0
+                   else if ((*q & ATTR_GBCHR) && ch == '#')
+                       *p++ = (unsigned char) 0xA3;
+#endif
+                   else
+                       *p++ = (unsigned char) ch;
+                   q++;
+               }
                if (nl) {
                    int i;
                    for (i=0; i<sizeof(sel_nl); i++)
index 5184bda..f51e412 100644 (file)
--- a/windlg.c
+++ b/windlg.c
@@ -392,13 +392,14 @@ static void staticbtn(struct ctlpos *cp, char *stext, int sid,
 /*
  * An edit control on the right hand side, with a static to its left.
  */
-static void staticedit(struct ctlpos *cp, char *stext, int sid, int eid) {
+static void staticedit(struct ctlpos *cp, char *stext,
+                       int sid, int eid, int percentedit) {
     const int height = (EDITHEIGHT > STATICHEIGHT ?
                         EDITHEIGHT : STATICHEIGHT);
     RECT r;
     int lwid, rwid, rpos;
 
-    rpos = GAPBETWEEN + (cp->width + GAPBETWEEN) / 2;
+    rpos = GAPBETWEEN + (100-percentedit) * (cp->width + GAPBETWEEN) / 100;
     lwid = rpos - 2*GAPBETWEEN;
     rwid = cp->width + GAPBETWEEN - rpos;
 
@@ -766,8 +767,8 @@ enum { IDCX_ABOUT = IDC_ABOUT, IDCX_TAB, controlstartvalue,
     IDC0_SESSLOAD,
     IDC0_SESSSAVE,
     IDC0_SESSDEL,
-    IDC0_CLOSEEXIT,
-    IDC0_CLOSEWARN,
+    IDC0_PINGSTATIC,
+    IDC0_PINGEDIT,
     connectionpanelend,
 
     keyboardpanelstart,
@@ -781,6 +782,7 @@ enum { IDCX_ABOUT = IDC_ABOUT, IDCX_TAB, controlstartvalue,
     IDC1_FUNCTILDE,
     IDC1_FUNCLINUX,
     IDC1_FUNCXTERM,
+    IDC1_FUNCVT400,
     IDC1_KPSTATIC,
     IDC1_KPNORMAL,
     IDC1_KPAPPLIC,
@@ -819,6 +821,8 @@ enum { IDCX_ABOUT = IDC_ABOUT, IDCX_TAB, controlstartvalue,
     IDC3_LOCKSIZE,
     IDC3_WINTITLE,
     IDC3_WINEDIT,
+    IDC3_CLOSEEXIT,
+    IDC3_CLOSEWARN,
     windowpanelend,
 
     telnetpanelstart,
@@ -948,18 +952,18 @@ static void init_dlg_ctrls(HWND hwnd) {
     CheckRadioButton (hwnd, IDC0_PROTRAW, IDC0_PROTSSH,
                      cfg.protocol==PROT_SSH ? IDC0_PROTSSH :
                      cfg.protocol==PROT_TELNET ? IDC0_PROTTELNET : IDC0_PROTRAW );
-    CheckDlgButton (hwnd, IDC0_CLOSEEXIT, cfg.close_on_exit);
-    CheckDlgButton (hwnd, IDC0_CLOSEWARN, cfg.warn_on_close);
+    SetDlgItemInt (hwnd, IDC0_PINGEDIT, cfg.ping_interval, FALSE);
 
     CheckRadioButton (hwnd, IDC1_DEL008, IDC1_DEL127,
                      cfg.bksp_is_delete ? IDC1_DEL127 : IDC1_DEL008);
     CheckRadioButton (hwnd, IDC1_HOMETILDE, IDC1_HOMERXVT,
                      cfg.rxvt_homeend ? IDC1_HOMERXVT : IDC1_HOMETILDE);
     CheckRadioButton (hwnd, IDC1_FUNCTILDE, IDC1_FUNCXTERM,
-                     cfg.funky_type ?
-                     (cfg.funky_type==2 ? IDC1_FUNCXTERM
-                      : IDC1_FUNCLINUX )
-                     : IDC1_FUNCTILDE);
+                      cfg.funky_type == 0 ? IDC1_FUNCTILDE :
+                      cfg.funky_type == 1 ? IDC1_FUNCLINUX :
+                      cfg.funky_type == 2 ? IDC1_FUNCXTERM :
+                      cfg.funky_type == 3 ? IDC1_FUNCVT400 :
+                      IDC1_FUNCTILDE );
     CheckRadioButton (hwnd, IDC1_CURNORMAL, IDC1_CURAPPLIC,
                      cfg.app_cursor ? IDC1_CURAPPLIC : IDC1_CURNORMAL);
     CheckRadioButton (hwnd, IDC1_KPNORMAL, IDC1_KPNH,
@@ -987,6 +991,8 @@ static void init_dlg_ctrls(HWND hwnd) {
     CheckDlgButton (hwnd, IDC3_BLINKCUR, cfg.blink_cur);
     CheckDlgButton (hwnd, IDC3_SCROLLBAR, cfg.scrollbar);
     CheckDlgButton (hwnd, IDC3_LOCKSIZE, cfg.locksize);
+    CheckDlgButton (hwnd, IDC3_CLOSEEXIT, cfg.close_on_exit);
+    CheckDlgButton (hwnd, IDC3_CLOSEWARN, cfg.warn_on_close);
 
     SetDlgItemText (hwnd, IDC4_TTEDIT, cfg.termtype);
     SetDlgItemText (hwnd, IDC4_TSEDIT, cfg.termspeed);
@@ -1155,8 +1161,8 @@ static int GenericMainDlgProc (HWND hwnd, UINT msg,
                          "&Save", IDC0_SESSSAVE,
                          "&Delete", IDC0_SESSDEL, NULL);
            }
-           checkbox(&cp, "Close Window on E&xit", IDC0_CLOSEEXIT);
-           checkbox(&cp, "&Warn on Close", IDC0_CLOSEWARN);
+            staticedit(&cp, "Keepalive inter&val (minutes)",
+                       IDC0_PINGSTATIC, IDC0_PINGEDIT, 25);
 
            tab.mask = TCIF_TEXT; tab.pszText = "Connection";
            TabCtrl_InsertItem (tabctl, i++, &tab);
@@ -1172,10 +1178,11 @@ static int GenericMainDlgProc (HWND hwnd, UINT msg,
            radioline(&cp, "Action of Home and End:", IDC1_HOMESTATIC, 2,
                      "&Standard", IDC1_HOMETILDE,
                      "&rxvt", IDC1_HOMERXVT, NULL);
-           radioline(&cp, "Function key and keypad layout:", IDC1_FUNCSTATIC, 3,
+           radioline(&cp, "Function key and keypad layout:", IDC1_FUNCSTATIC, 4,
                      "&VT400", IDC1_FUNCTILDE,
                      "&Linux", IDC1_FUNCLINUX,
-                     "&Xterm R6", IDC1_FUNCXTERM, NULL);
+                     "&Xterm R6", IDC1_FUNCXTERM,
+                      "&VT400", IDC1_FUNCVT400, NULL);
            radioline(&cp, "Initial state of cursor keys:", IDC1_CURSTATIC, 2,
                      "&Normal", IDC1_CURNORMAL,
                      "A&pplication", IDC1_CURAPPLIC, NULL);
@@ -1192,7 +1199,7 @@ static int GenericMainDlgProc (HWND hwnd, UINT msg,
            TabCtrl_InsertItem (tabctl, i++, &tab);
        }
 
-        /* The Terminal panel. Accelerators used: [aco] dghlmnprsw */
+        /* The Terminal panel. Accelerators used: [aco] dghlmnprsvw */
        {
            struct ctlpos cp;
            ctlposinit(&cp, hwnd, 6, 30);
@@ -1224,6 +1231,8 @@ static int GenericMainDlgProc (HWND hwnd, UINT msg,
            checkbox(&cp, "&Blinking cursor", IDC3_BLINKCUR);
            checkbox(&cp, "Displa&y scrollbar", IDC3_SCROLLBAR);
            checkbox(&cp, "Loc&k Window size", IDC3_LOCKSIZE);
+           checkbox(&cp, "Close Window on E&xit", IDC3_CLOSEEXIT);
+           checkbox(&cp, "&Warn on Close", IDC3_CLOSEWARN);
            tab.mask = TCIF_TEXT; tab.pszText = "Window";
            TabCtrl_InsertItem (tabctl, i++, &tab);
        }
@@ -1233,9 +1242,9 @@ static int GenericMainDlgProc (HWND hwnd, UINT msg,
            struct ctlpos cp;
            ctlposinit(&cp, hwnd, 6, 30);
            if (dlgtype == 0) {
-               staticedit(&cp, "Terminal-&type string", IDC4_TTSTATIC, IDC4_TTEDIT);
-               staticedit(&cp, "Terminal-&speed string", IDC4_TSSTATIC, IDC4_TSEDIT);
-               staticedit(&cp, "Auto-login &username", IDC4_LOGSTATIC, IDC4_LOGEDIT);
+               staticedit(&cp, "Terminal-&type string", IDC4_TTSTATIC, IDC4_TTEDIT, 50);
+               staticedit(&cp, "Terminal-&speed string", IDC4_TSSTATIC, IDC4_TSEDIT, 50);
+               staticedit(&cp, "Auto-login &username", IDC4_LOGSTATIC, IDC4_LOGEDIT, 50);
                envsetter(&cp, "Environment variables:", IDC4_ENVSTATIC,
                          "&Variable", IDC4_VARSTATIC, IDC4_VAREDIT,
                          "Va&lue", IDC4_VALSTATIC, IDC4_VALEDIT,
@@ -1254,8 +1263,8 @@ static int GenericMainDlgProc (HWND hwnd, UINT msg,
            struct ctlpos cp;
            ctlposinit(&cp, hwnd, 6, 30);
            if (dlgtype == 0) {
-               staticedit(&cp, "Terminal-&type string", IDC5_TTSTATIC, IDC5_TTEDIT);
-               staticedit(&cp, "Auto-login &username", IDC5_LOGSTATIC, IDC5_LOGEDIT);
+               staticedit(&cp, "Terminal-&type string", IDC5_TTSTATIC, IDC5_TTEDIT, 50);
+               staticedit(&cp, "Auto-login &username", IDC5_LOGSTATIC, IDC5_LOGEDIT, 50);
                multiedit(&cp,
                          "&Remote command:", IDC5_CMDSTATIC, IDC5_CMDEDIT, 100,
                          NULL);
@@ -1340,7 +1349,7 @@ static int GenericMainDlgProc (HWND hwnd, UINT msg,
         {
             HWND ctl;
             ctl = GetDlgItem(hwnd, IDC0_HOST);
-            if (!ctl) ctl = GetDlgItem(hwnd, IDC0_CLOSEEXIT);
+            if (!ctl) ctl = GetDlgItem(hwnd, IDC0_PINGEDIT);
             SetFocus(ctl);
         }
 
@@ -1427,16 +1436,6 @@ static int GenericMainDlgProc (HWND hwnd, UINT msg,
            if (HIWORD(wParam) == EN_CHANGE)
                MyGetDlgItemInt (hwnd, IDC0_PORT, &cfg.port);
            break;
-         case IDC0_CLOSEEXIT:
-           if (HIWORD(wParam) == BN_CLICKED ||
-               HIWORD(wParam) == BN_DOUBLECLICKED)
-               cfg.close_on_exit = IsDlgButtonChecked (hwnd, IDC0_CLOSEEXIT);
-           break;
-         case IDC0_CLOSEWARN:
-           if (HIWORD(wParam) == BN_CLICKED ||
-               HIWORD(wParam) == BN_DOUBLECLICKED)
-               cfg.warn_on_close = IsDlgButtonChecked (hwnd, IDC0_CLOSEWARN);
-           break;
          case IDC0_SESSEDIT:
            if (HIWORD(wParam) == EN_CHANGE) {
                SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
@@ -1529,6 +1528,10 @@ static int GenericMainDlgProc (HWND hwnd, UINT msg,
                SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
                                    (WPARAM) -1, 0);
            }
+          case IDC0_PINGEDIT:
+            if (HIWORD(wParam) == EN_CHANGE)
+                MyGetDlgItemInt (hwnd, IDC0_PINGEDIT, &cfg.ping_interval);
+            break;
          case IDC1_DEL008:
          case IDC1_DEL127:
            if (HIWORD(wParam) == BN_CLICKED ||
@@ -1546,6 +1549,11 @@ static int GenericMainDlgProc (HWND hwnd, UINT msg,
                HIWORD(wParam) == BN_DOUBLECLICKED)
                cfg.funky_type = 2;
            break;
+         case IDC1_FUNCVT400:
+           if (HIWORD(wParam) == BN_CLICKED ||
+               HIWORD(wParam) == BN_DOUBLECLICKED)
+               cfg.funky_type = 3;
+           break;
          case IDC1_FUNCTILDE:
          case IDC1_FUNCLINUX:
            if (HIWORD(wParam) == BN_CLICKED ||
@@ -1689,6 +1697,16 @@ static int GenericMainDlgProc (HWND hwnd, UINT msg,
                GetDlgItemText (hwnd, IDC3_WINEDIT, cfg.wintitle,
                                sizeof(cfg.wintitle)-1);
            break;
+         case IDC3_CLOSEEXIT:
+           if (HIWORD(wParam) == BN_CLICKED ||
+               HIWORD(wParam) == BN_DOUBLECLICKED)
+               cfg.close_on_exit = IsDlgButtonChecked (hwnd, IDC3_CLOSEEXIT);
+           break;
+         case IDC3_CLOSEWARN:
+           if (HIWORD(wParam) == BN_CLICKED ||
+               HIWORD(wParam) == BN_DOUBLECLICKED)
+               cfg.warn_on_close = IsDlgButtonChecked (hwnd, IDC3_CLOSEWARN);
+           break;
          case IDC4_TTEDIT:
            if (HIWORD(wParam) == EN_CHANGE)
            GetDlgItemText (hwnd, IDC4_TTEDIT, cfg.termtype,
index 7b7dee1..822cb01 100644 (file)
--- a/window.c
+++ b/window.c
@@ -10,6 +10,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <ctype.h>
+#include <time.h>
 
 #define PUTTY_DO_GLOBALS                      /* actually _define_ globals */
 #include "putty.h"
@@ -57,6 +58,8 @@ static WPARAM pend_netevent_wParam = 0;
 static LPARAM pend_netevent_lParam = 0;
 static void enact_pending_netevent(void);
 
+static time_t last_movement = 0;
+
 #define FONT_NORMAL 0
 #define FONT_BOLD 1
 #define FONT_UNDERLINE 2
@@ -512,10 +515,11 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) {
     has_focus = (GetForegroundWindow() == hwnd);
     UpdateWindow (hwnd);
 
+    if (GetMessage (&msg, NULL, 0, 0) == 1)
     {
        int timer_id = 0, long_timer = 0;
 
-       while (GetMessage (&msg, NULL, 0, 0) == 1) {
+       while (msg.message != WM_QUIT) {
            /* Sometimes DispatchMessage calls routines that use their own
             * GetMessage loop, setup this timer so we get some control back.
             *
@@ -530,9 +534,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) {
                timer_id = SetTimer(hwnd, 1, 20, NULL);
            DispatchMessage (&msg);
 
-           /* This is too fast, but I'll leave it for now 'cause it shows
-            * how often term_update is called (far too often at times!)
-            */
+           /* Make sure we blink everything that needs it. */
            term_blink(0);
 
            /* Send the paste buffer if there's anything to send */
@@ -542,31 +544,44 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) {
             * we've delayed, reading the socket, writing, and repainting
             * the window.
             */
-           if (!PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)) {
-               if (pending_netevent) {
-                   enact_pending_netevent();
+           if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
+               continue;
 
-                   term_blink(1);
-               }
-           } else continue;
-           if (!PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)) {
-               if (timer_id) {
-                   KillTimer(hwnd, timer_id);
-                   timer_id = 0;
-               }
-                HideCaret(hwnd);
-               if (inbuf_head)
-                   term_out();
-               term_update();
-                ShowCaret(hwnd);
-               if (!has_focus)
-                  timer_id = SetTimer(hwnd, 1, 2000, NULL);
-               else if (cfg.blinktext)
-                  timer_id = SetTimer(hwnd, 1, 250, NULL);
-               else
-                  timer_id = SetTimer(hwnd, 1, 500, NULL);
-               long_timer = 1;
+           if (pending_netevent) {
+               enact_pending_netevent();
+
+               /* Force the cursor blink on */
+               term_blink(1);
+
+               if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
+                   continue;
            }
+
+           /* Okay there is now nothing to do so we make sure the screen is
+            * completely up to date then tell windows to call us in a little 
+            * while.
+            */
+           if (timer_id) {
+               KillTimer(hwnd, timer_id);
+               timer_id = 0;
+           }
+            HideCaret(hwnd);
+           if (inbuf_head)
+               term_out();
+           term_update();
+            ShowCaret(hwnd);
+           if (!has_focus)
+              timer_id = SetTimer(hwnd, 1, 59500, NULL);
+           else
+              timer_id = SetTimer(hwnd, 1, 250, NULL);
+           long_timer = 1;
+       
+           /* There's no point rescanning everything in the message queue
+            * so we do an apperently unneccesary wait here 
+            */
+           WaitMessage();
+           if (GetMessage (&msg, NULL, 0, 0) != 1)
+               break;
        }
     }
 
@@ -1013,6 +1028,16 @@ static LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
         HideCaret(hwnd);
        term_update();
         ShowCaret(hwnd);
+       if (cfg.ping_interval > 0)
+        {
+           time_t now;
+           time(&now);
+           if (now-last_movement > cfg.ping_interval * 60 - 10)
+           {
+              back->special(TS_PING);
+              last_movement = now;
+           }
+        }
        return 0;
       case WM_CREATE:
        break;
@@ -1290,6 +1315,7 @@ static LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
        pending_netevent = TRUE;
        pend_netevent_wParam=wParam;
        pend_netevent_lParam=lParam;
+       time(&last_movement);
        return 0;
       case WM_SETFOCUS:
        has_focus = TRUE;
@@ -1569,16 +1595,7 @@ void do_text (Context ctx, int x, int y, char *text, int len,
            }
     }
 
-    if (attr & ATTR_GBCHR) {
-       int i;
-       /*
-        * GB mapping: map # to pound, and everything else stays
-        * normal.
-        */
-       for (i=0; i<len; i++)
-           if (text[i] == '#')
-               text[i] = cfg.vtmode == VT_OEMONLY ? '\x9C' : '\xA3';
-    } else if (attr & ATTR_LINEDRW) {
+    if (attr & ATTR_LINEDRW) {
        int i;
        /* ISO 8859-1 */
        static const char poorman[] =
@@ -1602,6 +1619,8 @@ void do_text (Context ctx, int x, int y, char *text, int len,
        /*
         * Line drawing mapping: map ` thru ~ (0x60 thru 0x7E) to
         * VT100 line drawing chars; everything else stays normal.
+        *
+        * Actually '_' maps to space too, but that's done before.
         */
        switch (cfg.vtmode) {
          case VT_XWINDOWS:
@@ -1767,6 +1786,63 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, unsigned cha
     if (!r) memset(keystate, 0, sizeof(keystate));
     else
     {
+#if 0
+       {  /* Tell us all about key events */
+         static BYTE oldstate[256];
+         static int first = 1;
+         static int scan;
+         int ch;
+         if(first) memcpy(oldstate, keystate, sizeof(oldstate));
+         first=0;
+
+         if ((HIWORD(lParam)&(KF_UP|KF_REPEAT))==KF_REPEAT) {
+            debug(("+"));
+         } else if ((HIWORD(lParam)&KF_UP) && scan==(HIWORD(lParam) & 0xFF) ) {
+            debug((". U"));
+         } else {
+            debug((".\n"));
+            if (wParam >= VK_F1 && wParam <= VK_F20 )
+               debug(("K_F%d", wParam+1-VK_F1));
+            else switch(wParam)
+            {
+            case VK_SHIFT:   debug(("SHIFT")); break;
+            case VK_CONTROL: debug(("CTRL")); break;
+            case VK_MENU:    debug(("ALT")); break;
+            default:         debug(("VK_%02x", wParam));
+            }
+            if(message == WM_SYSKEYDOWN || message == WM_SYSKEYUP)
+               debug(("*"));
+            debug((", S%02x", scan=(HIWORD(lParam) & 0xFF) ));
+
+            ch = MapVirtualKey(wParam, 2);
+            if (ch>=' ' && ch<='~') debug((", '%c'", ch));
+            else if (ch)            debug((", $%02x", ch));
+
+            if (keys[0]) debug((", KB0=%02x", keys[0]));
+            if (keys[1]) debug((", KB1=%02x", keys[1]));
+            if (keys[2]) debug((", KB2=%02x", keys[2]));
+
+            if ( (keystate[VK_SHIFT]&0x80)!=0)     debug((", S"));
+            if ( (keystate[VK_CONTROL]&0x80)!=0)   debug((", C"));
+            if ( (HIWORD(lParam)&KF_EXTENDED) )    debug((", E"));
+            if ( (HIWORD(lParam)&KF_UP) )          debug((", U"));
+         }
+
+         if ((HIWORD(lParam)&(KF_UP|KF_REPEAT))==KF_REPEAT)
+            ;
+         else if ( (HIWORD(lParam)&KF_UP) ) 
+            oldstate[wParam&0xFF] ^= 0x80;
+         else
+            oldstate[wParam&0xFF] ^= 0x81;
+
+         for(ch=0; ch<256; ch++)
+            if (oldstate[ch] != keystate[ch])
+               debug((", M%02x=%02x", ch, keystate[ch]));
+
+         memcpy(oldstate, keystate, sizeof(oldstate));
+       }
+#endif
+
        /* Note if AltGr was pressed and if it was used as a compose key */
        if (wParam == VK_MENU && (HIWORD(lParam)&KF_EXTENDED))
        {
@@ -1789,7 +1865,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, unsigned cha
           compose_state = 0;
 
        /* Nastyness with NUMLock - Shift-NUMLock is left alone though */
-       if ( (cfg.funky_type == 0 || (cfg.funky_type == 1 && app_keypad_keys))
+       if ( (cfg.funky_type == 3 || (cfg.funky_type <= 1 && app_keypad_keys))
              && wParam==VK_NUMLOCK && !(keystate[VK_SHIFT]&0x80)) {
 
            wParam = VK_EXECUTE;
@@ -1835,7 +1911,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, unsigned cha
 
     /* Sanitize the number pad if not using a PC NumPad */
     if( left_alt || (app_keypad_keys && cfg.funky_type != 2)
-         || cfg.nethack_keypad || compose_state )
+       || cfg.funky_type == 3 || cfg.nethack_keypad || compose_state )
     {
        if ((HIWORD(lParam)&KF_EXTENDED) == 0)
        {
@@ -1890,6 +1966,11 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, unsigned cha
             SendMessage (hwnd, WM_SYSCOMMAND, SC_KEYMENU, 0);
             return -1;
        }
+       /* Control-Numlock for app-keypad mode switch */
+       if (wParam == VK_PAUSE && shift_state == 2) {
+           app_keypad_keys ^= 1;
+           return 0;
+       }
 
        /* Nethack keypad */
        if (cfg.nethack_keypad && !left_alt) {
@@ -1910,9 +1991,9 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, unsigned cha
        if (!left_alt) {
           int xkey = 0;
 
-          if ( cfg.funky_type == 0 ||
-             ( cfg.funky_type == 1 && app_keypad_keys)) switch(wParam) {
-              case VK_EXECUTE: if (app_keypad_keys) xkey = 'P'; break;
+          if ( cfg.funky_type == 3 ||
+             ( cfg.funky_type <= 1 && app_keypad_keys)) switch(wParam) {
+              case VK_EXECUTE: xkey = 'P'; break;
               case VK_DIVIDE:  xkey = 'Q'; break;
               case VK_MULTIPLY:xkey = 'R'; break;
               case VK_SUBTRACT:xkey = 'S'; break;
@@ -1930,9 +2011,17 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, unsigned cha
               case VK_NUMPAD9: xkey = 'y'; break;
 
               case VK_DECIMAL: xkey = 'n'; break;
-              case VK_ADD:     if(shift_state) xkey = 'm'; 
-                               else            xkey = 'l';
+              case VK_ADD:     if(cfg.funky_type==2) { 
+                                   if(shift_state) xkey = 'l';
+                                   else            xkey = 'k';
+                               } else if(shift_state)  xkey = 'm'; 
+                                 else                  xkey = 'l';
                                break;
+
+              case VK_DIVIDE:  if(cfg.funky_type==2) xkey = 'o'; break;
+              case VK_MULTIPLY:if(cfg.funky_type==2) xkey = 'j'; break;
+              case VK_SUBTRACT:if(cfg.funky_type==2) xkey = 'm'; break;
+
               case VK_RETURN:
                                if (HIWORD(lParam)&KF_EXTENDED)
                                    xkey = 'M';
@@ -2031,12 +2120,18 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, unsigned cha
          case VK_PRIOR: code = 5; break;
          case VK_NEXT: code = 6; break;
        }
+       /* Reorder edit keys to physical order */
+       if (cfg.funky_type == 3 && code <= 6 ) code = "\0\2\1\4\5\3\6"[code];
+
        if (cfg.funky_type == 1 && code >= 11 && code <= 15) {
            p += sprintf((char *)p, "\x1B[[%c", code + 'A' - 11);
            return p - output;
        }
        if (cfg.funky_type == 2 && code >= 11 && code <= 14) {
-           p += sprintf((char *)p, "\x1BO%c", code + 'P' - 11);
+           if (vt52_mode)
+               p += sprintf((char *)p, "\x1B%c", code + 'P' - 11);
+           else
+               p += sprintf((char *)p, "\x1BO%c", code + 'P' - 11);
            return p - output;
        }
        if (cfg.rxvt_homeend && (code == 1 || code == 4)) {
@@ -2141,10 +2236,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, unsigned cha
 
     /* This stops ALT press-release doing a 'COMMAND MENU' function */
     if (message == WM_SYSKEYUP && wParam == VK_MENU) 
-    {
-       keystate[VK_MENU] = 0;
        return 0;
-    }
 
     return -1;
 }