Loose end from r5031: the Kex panel should only be displayed in
[u/mdw/putty] / config.c
index 184023d..6a5961c 100644 (file)
--- a/config.c
+++ b/config.c
@@ -124,6 +124,48 @@ static void cipherlist_handler(union control *ctrl, void *dlg,
     }
 }
 
+static void kexlist_handler(union control *ctrl, void *dlg,
+                           void *data, int event)
+{
+    Config *cfg = (Config *)data;
+    if (event == EVENT_REFRESH) {
+       int i;
+
+       static const struct { char *s; int k; } kexes[] = {
+           { "Diffie-Hellman group 1",         KEX_DHGROUP1 },
+           { "Diffie-Hellman group 14",        KEX_DHGROUP14 },
+           { "Diffie-Hellman group exchange",  KEX_DHGEX },
+           { "-- warn below here --",          KEX_WARN }
+       };
+
+       /* Set up the "kex preference" box. */
+       /* (kexlist assumed to contain all algorithms) */
+       dlg_update_start(ctrl, dlg);
+       dlg_listbox_clear(ctrl, dlg);
+       for (i = 0; i < KEX_MAX; i++) {
+           int k = cfg->ssh_kexlist[i];
+           int j;
+           char *kstr = NULL;
+           for (j = 0; j < (sizeof kexes) / (sizeof kexes[0]); j++) {
+               if (kexes[j].k == k) {
+                   kstr = kexes[j].s;
+                   break;
+               }
+           }
+           dlg_listbox_addwithid(ctrl, dlg, kstr, k);
+       }
+       dlg_update_done(ctrl, dlg);
+
+    } else if (event == EVENT_VALCHANGE) {
+       int i;
+
+       /* Update array to match the list box. */
+       for (i=0; i < KEX_MAX; i++)
+           cfg->ssh_kexlist[i] = dlg_listbox_getid(ctrl, dlg, i);
+
+    }
+}
+
 static void printerbox_handler(union control *ctrl, void *dlg,
                               void *data, int event)
 {
@@ -256,8 +298,12 @@ static void sessionsaver_handler(union control *ctrl, void *dlg,
      * allocate space to store the current contents of the saved
      * session edit box (since it must persist even when we switch
      * panels, but is not part of the Config).
+     * 
+     * Of course, this doesn't need to be done mid-session.
      */
-    if (!dlg_get_privdata(ssd->editbox, dlg)) {
+    if (!ssd->editbox) {
+        savedsession = NULL;
+    } else if (!dlg_get_privdata(ssd->editbox, dlg)) {
        savedsession = (char *)
            dlg_alloc_privdata(ssd->editbox, dlg, SAVEDSESSION_LEN);
        savedsession[0] = '\0';
@@ -333,6 +379,11 @@ static void sessionsaver_handler(union control *ctrl, void *dlg,
                dlg_refresh(ssd->listbox, dlg);
            }
        } else if (ctrl == ssd->okbutton) {
+            if (!savedsession) {
+                /* In a mid-session Change Settings, Apply is always OK. */
+               dlg_end(dlg, 1);
+                return;
+            }
            /*
             * Annoying special case. If the `Open' button is
             * pressed while no host name is currently set, _and_
@@ -349,9 +400,11 @@ static void sessionsaver_handler(union control *ctrl, void *dlg,
                /* If at this point we have a valid session, go! */
                if (*cfg2.host) {
                    *cfg = cfg2;       /* structure copy */
+                   cfg->remote_cmd_ptr = cfg->remote_cmd; /* nasty */
                    dlg_end(dlg, 1);
                } else
                    dlg_beep(dlg);
+                return;
            }
 
            /*
@@ -717,7 +770,7 @@ static void portfwd_handler(union control *ctrl, void *dlg,
 }
 
 void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
-                     int midsession, int protocol)
+                     int midsession, int protocol, int protcfginfo)
 {
     struct controlset *s;
     struct sessionsaver_data *ssd;
@@ -730,6 +783,7 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
 
     ssd = (struct sessionsaver_data *)
        ctrl_alloc(b, sizeof(struct sessionsaver_data));
+    memset(ssd, 0, sizeof(*ssd));
     ssd->sesslist = (midsession ? NULL : sesslist);
 
     /*
@@ -791,39 +845,42 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
                              "SSH", 's', I(PROT_SSH),
                              NULL);
        }
-
-       s = ctrl_getset(b, "Session", "savedsessions",
-                       "Load, save or delete a stored session");
-       ctrl_columns(s, 2, 75, 25);
-       ssd->sesslist = sesslist;
-       ssd->editbox = ctrl_editbox(s, "Saved Sessions", 'e', 100,
-                                   HELPCTX(session_saved),
-                                   sessionsaver_handler, P(ssd), P(NULL));
-       ssd->editbox->generic.column = 0;
-       /* Reset columns so that the buttons are alongside the list, rather
-        * than alongside that edit box. */
-       ctrl_columns(s, 1, 100);
-       ctrl_columns(s, 2, 75, 25);
-       ssd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
-                                   HELPCTX(session_saved),
-                                   sessionsaver_handler, P(ssd));
-       ssd->listbox->generic.column = 0;
-       ssd->listbox->listbox.height = 7;
-       ssd->loadbutton = ctrl_pushbutton(s, "Load", 'l',
-                                         HELPCTX(session_saved),
-                                         sessionsaver_handler, P(ssd));
-       ssd->loadbutton->generic.column = 1;
-       ssd->savebutton = ctrl_pushbutton(s, "Save", 'v',
-                                         HELPCTX(session_saved),
-                                         sessionsaver_handler, P(ssd));
-       ssd->savebutton->generic.column = 1;
-       ssd->delbutton = ctrl_pushbutton(s, "Delete", 'd',
-                                        HELPCTX(session_saved),
-                                        sessionsaver_handler, P(ssd));
-       ssd->delbutton->generic.column = 1;
-       ctrl_columns(s, 1, 100);
     }
 
+    /*
+     * The Load/Save panel is available even in mid-session.
+     */
+    s = ctrl_getset(b, "Session", "savedsessions",
+                   "Load, save or delete a stored session");
+    ctrl_columns(s, 2, 75, 25);
+    ssd->sesslist = sesslist;
+    ssd->editbox = ctrl_editbox(s, "Saved Sessions", 'e', 100,
+                               HELPCTX(session_saved),
+                               sessionsaver_handler, P(ssd), P(NULL));
+    ssd->editbox->generic.column = 0;
+    /* Reset columns so that the buttons are alongside the list, rather
+     * than alongside that edit box. */
+    ctrl_columns(s, 1, 100);
+    ctrl_columns(s, 2, 75, 25);
+    ssd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
+                               HELPCTX(session_saved),
+                               sessionsaver_handler, P(ssd));
+    ssd->listbox->generic.column = 0;
+    ssd->listbox->listbox.height = 7;
+    ssd->loadbutton = ctrl_pushbutton(s, "Load", 'l',
+                                     HELPCTX(session_saved),
+                                     sessionsaver_handler, P(ssd));
+    ssd->loadbutton->generic.column = 1;
+    ssd->savebutton = ctrl_pushbutton(s, "Save", 'v',
+                                     HELPCTX(session_saved),
+                                     sessionsaver_handler, P(ssd));
+    ssd->savebutton->generic.column = 1;
+    ssd->delbutton = ctrl_pushbutton(s, "Delete", 'd',
+                                    HELPCTX(session_saved),
+                                    sessionsaver_handler, P(ssd));
+    ssd->delbutton->generic.column = 1;
+    ctrl_columns(s, 1, 100);
+
     s = ctrl_getset(b, "Session", "otheropts", NULL);
     c = ctrl_radiobuttons(s, "Close window on exit:", 'w', 4,
                          HELPCTX(session_coe),
@@ -839,14 +896,27 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
     ctrl_settitle(b, "Session/Logging", "Options controlling session logging");
 
     s = ctrl_getset(b, "Session/Logging", "main", NULL);
-    ctrl_radiobuttons(s, "Session logging:", NO_SHORTCUT, 1,
-                     HELPCTX(logging_main),
-                     dlg_stdradiobutton_handler, I(offsetof(Config, logtype)),
-                     "Logging turned off completely", 't', I(LGTYP_NONE),
-                     "Log printable output only", 'p', I(LGTYP_ASCII),
-                     "Log all session output", 'l', I(LGTYP_DEBUG),
-                     "Log SSH packet data", 's', I(LGTYP_PACKETS),
-                     NULL);
+    /*
+     * The logging buttons change depending on whether SSH packet
+     * logging can sensibly be available.
+     */
+    {
+       char *sshlogname;
+       if ((midsession && protocol == PROT_SSH) ||
+           (!midsession && backends[3].name != NULL))
+           sshlogname = "Log SSH packet data";
+       else
+           sshlogname = NULL;         /* this will disable the button */
+       ctrl_radiobuttons(s, "Session logging:", NO_SHORTCUT, 1,
+                         HELPCTX(logging_main),
+                         dlg_stdradiobutton_handler,
+                         I(offsetof(Config, logtype)),
+                         "Logging turned off completely", 't', I(LGTYP_NONE),
+                         "Log printable output only", 'p', I(LGTYP_ASCII),
+                         "Log all session output", 'l', I(LGTYP_DEBUG),
+                         sshlogname, 's', I(LGTYP_PACKETS),
+                         NULL);
+    }
     ctrl_filesel(s, "Log file name:", 'f',
                 NULL, TRUE, "Select session log file name",
                 HELPCTX(logging_filename),
@@ -860,6 +930,21 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
                      "Always overwrite it", I(LGXF_OVR),
                      "Always append to the end of it", I(LGXF_APN),
                      "Ask the user every time", I(LGXF_ASK), NULL);
+    ctrl_checkbox(s, "Flush log file frequently", 'u',
+                HELPCTX(logging_flush),
+                dlg_stdcheckbox_handler, I(offsetof(Config,logflush)));
+
+    if ((midsession && protocol == PROT_SSH) ||
+       (!midsession && backends[3].name != NULL)) {
+       s = ctrl_getset(b, "Session/Logging", "ssh",
+                       "Options specific to SSH packet logging");
+       ctrl_checkbox(s, "Omit known password fields", 'k',
+                     HELPCTX(logging_ssh_omit_password),
+                     dlg_stdcheckbox_handler, I(offsetof(Config,logomitpass)));
+       ctrl_checkbox(s, "Omit session data", 'd',
+                     HELPCTX(logging_ssh_omit_data),
+                     dlg_stdcheckbox_handler, I(offsetof(Config,logomitdata)));
+    }
 
     /*
      * The Terminal panel.
@@ -1004,12 +1089,21 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
                  HELPCTX(features_retitle),
                  dlg_stdcheckbox_handler,
                  I(offsetof(Config,no_remote_wintitle)));
+    ctrl_checkbox(s, "Disable remote window title querying (SECURITY)",
+                 'q', HELPCTX(features_qtitle), dlg_stdcheckbox_handler,
+                 I(offsetof(Config,no_remote_qtitle)));
     ctrl_checkbox(s, "Disable destructive backspace on server sending ^?",'b',
                  HELPCTX(features_dbackspace),
                  dlg_stdcheckbox_handler, I(offsetof(Config,no_dbackspace)));
     ctrl_checkbox(s, "Disable remote-controlled character set configuration",
                  'r', HELPCTX(features_charset), dlg_stdcheckbox_handler,
                  I(offsetof(Config,no_remote_charset)));
+    ctrl_checkbox(s, "Disable Arabic text shaping",
+                 'l', HELPCTX(features_arabicshaping), dlg_stdcheckbox_handler,
+                 I(offsetof(Config, arabicshaping)));
+    ctrl_checkbox(s, "Disable bidirectional text display",
+                 'd', HELPCTX(features_bidi), dlg_stdcheckbox_handler,
+                 I(offsetof(Config, bidi)));
 
     /*
      * The Window panel.
@@ -1123,27 +1217,24 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
                  'r', 100, HELPCTX(translation_codepage),
                  codepage_handler, P(NULL), P(NULL));
 
-    str = dupprintf("Adjust how %s displays line drawing characters", appname);
+    str = dupprintf("Adjust how %s handles line drawing characters", appname);
     s = ctrl_getset(b, "Window/Translation", "linedraw", str);
     sfree(str);
     ctrl_radiobuttons(s, "Handling of line drawing characters:", NO_SHORTCUT,1,
                      HELPCTX(translation_linedraw),
                      dlg_stdradiobutton_handler,
                      I(offsetof(Config, vtmode)),
-                     "Font has XWindows encoding", 'x', I(VT_XWINDOWS),
+                     "Use Unicode line drawing code points",'u',I(VT_UNICODE),
                      "Poor man's line drawing (+, - and |)",'p',I(VT_POORMAN),
-                     "Unicode mode", 'u', I(VT_UNICODE), NULL);
+                     NULL);
+    ctrl_checkbox(s, "Copy and paste line drawing characters as lqqqk",'d',
+                 HELPCTX(selection_linedraw),
+                 dlg_stdcheckbox_handler, I(offsetof(Config,rawcnp)));
 
     /*
      * The Window/Selection panel.
      */
     ctrl_settitle(b, "Window/Selection", "Options controlling copy and paste");
-
-    s = ctrl_getset(b, "Window/Selection", "trans",
-                   "Translation of pasted characters");
-    ctrl_checkbox(s, "Don't translate line drawing chars into +, - and |",'d',
-                 HELPCTX(selection_linedraw),
-                 dlg_stdcheckbox_handler, I(offsetof(Config,rawcnp)));
        
     s = ctrl_getset(b, "Window/Selection", "mouse",
                    "Control use of mouse");
@@ -1191,6 +1282,12 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
 
     s = ctrl_getset(b, "Window/Colours", "general",
                    "General options for colour usage");
+    ctrl_checkbox(s, "Allow terminal to specify ANSI colours", 'i',
+                 HELPCTX(colours_ansi),
+                 dlg_stdcheckbox_handler, I(offsetof(Config,ansi_colour)));
+    ctrl_checkbox(s, "Allow terminal to use xterm 256-colour mode", '2',
+                 HELPCTX(colours_xterm256), dlg_stdcheckbox_handler,
+                 I(offsetof(Config,xterm_256_colour)));
     ctrl_checkbox(s, "Bolded text is a different colour", 'b',
                  HELPCTX(colours_bold),
                  dlg_stdcheckbox_handler, I(offsetof(Config,bold_colour)));
@@ -1224,36 +1321,80 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
     ctrl_columns(s, 1, 100);
 
     /*
-     * The Connection panel.
+     * The Connection panel. This doesn't show up if we're in a
+     * non-network utility such as pterm. We tell this by being
+     * passed a protocol < 0.
      */
-    ctrl_settitle(b, "Connection", "Options controlling the connection");
+    if (protocol >= 0) {
+       ctrl_settitle(b, "Connection", "Options controlling the connection");
 
-    if (!midsession) {
-       s = ctrl_getset(b, "Connection", "data", "Data to send to the server");
-       ctrl_editbox(s, "Terminal-type string", 't', 50,
-                    HELPCTX(connection_termtype),
-                    dlg_stdeditbox_handler, I(offsetof(Config,termtype)),
-                    I(sizeof(((Config *)0)->termtype)));
-       ctrl_editbox(s, "Auto-login username", 'u', 50,
-                    HELPCTX(connection_username),
-                    dlg_stdeditbox_handler, I(offsetof(Config,username)),
-                    I(sizeof(((Config *)0)->username)));
-    }
+       if (!midsession) {
+           s = ctrl_getset(b, "Connection", "data",
+                           "Data to send to the server");
+           ctrl_editbox(s, "Terminal-type string", 't', 50,
+                        HELPCTX(connection_termtype),
+                        dlg_stdeditbox_handler, I(offsetof(Config,termtype)),
+                        I(sizeof(((Config *)0)->termtype)));
+           ctrl_editbox(s, "Terminal speeds", 's', 50,
+                        HELPCTX(connection_termspeed),
+                        dlg_stdeditbox_handler, I(offsetof(Config,termspeed)),
+                        I(sizeof(((Config *)0)->termspeed)));
+           ctrl_editbox(s, "Auto-login username", 'u', 50,
+                        HELPCTX(connection_username),
+                        dlg_stdeditbox_handler, I(offsetof(Config,username)),
+                        I(sizeof(((Config *)0)->username)));
+
+           ctrl_text(s, "Environment variables:", HELPCTX(telnet_environ));
+           ctrl_columns(s, 2, 80, 20);
+           ed = (struct environ_data *)
+               ctrl_alloc(b, sizeof(struct environ_data));
+           ed->varbox = ctrl_editbox(s, "Variable", 'v', 60,
+                                     HELPCTX(telnet_environ),
+                                     environ_handler, P(ed), P(NULL));
+           ed->varbox->generic.column = 0;
+           ed->valbox = ctrl_editbox(s, "Value", 'l', 60,
+                                     HELPCTX(telnet_environ),
+                                     environ_handler, P(ed), P(NULL));
+           ed->valbox->generic.column = 0;
+           ed->addbutton = ctrl_pushbutton(s, "Add", 'd',
+                                           HELPCTX(telnet_environ),
+                                           environ_handler, P(ed));
+           ed->addbutton->generic.column = 1;
+           ed->rembutton = ctrl_pushbutton(s, "Remove", 'r',
+                                           HELPCTX(telnet_environ),
+                                           environ_handler, P(ed));
+           ed->rembutton->generic.column = 1;
+           ctrl_columns(s, 1, 100);
+           ed->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
+                                      HELPCTX(telnet_environ),
+                                      environ_handler, P(ed));
+           ed->listbox->listbox.height = 3;
+           ed->listbox->listbox.ncols = 2;
+           ed->listbox->listbox.percentages = snewn(2, int);
+           ed->listbox->listbox.percentages[0] = 30;
+           ed->listbox->listbox.percentages[1] = 70;
+       }
 
-    s = ctrl_getset(b, "Connection", "keepalive",
-                   "Sending of null packets to keep session active");
-    ctrl_editbox(s, "Seconds between keepalives (0 to turn off)", 'k', 20,
-                HELPCTX(connection_keepalive),
-                dlg_stdeditbox_handler, I(offsetof(Config,ping_interval)),
-                I(-1));
+       s = ctrl_getset(b, "Connection", "keepalive",
+                       "Sending of null packets to keep session active");
+       ctrl_editbox(s, "Seconds between keepalives (0 to turn off)", 'k', 20,
+                    HELPCTX(connection_keepalive),
+                    dlg_stdeditbox_handler, I(offsetof(Config,ping_interval)),
+                    I(-1));
+
+       if (!midsession) {
+           s = ctrl_getset(b, "Connection", "tcp",
+                           "Low-level TCP connection options");
+           ctrl_checkbox(s, "Disable Nagle's algorithm (TCP_NODELAY option)",
+                         'n', HELPCTX(connection_nodelay),
+                         dlg_stdcheckbox_handler,
+                         I(offsetof(Config,tcp_nodelay)));
+           ctrl_checkbox(s, "Enable TCP keepalives (SO_KEEPALIVE option)",
+                         'p', HELPCTX(connection_tcpkeepalive),
+                         dlg_stdcheckbox_handler,
+                         I(offsetof(Config,tcp_keepalives)));
+       }
 
-    if (!midsession) {
-       s = ctrl_getset(b, "Connection", "tcp",
-                       "Low-level TCP connection options");
-       ctrl_checkbox(s, "Disable Nagle's algorithm (TCP_NODELAY option)", 'n',
-                     HELPCTX(connection_nodelay),
-                     dlg_stdcheckbox_handler,
-                     I(offsetof(Config,tcp_nodelay)));
     }
 
     if (!midsession) {
@@ -1263,15 +1404,16 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
        ctrl_settitle(b, "Connection/Proxy",
                      "Options controlling proxy usage");
 
-       s = ctrl_getset(b, "Connection/Proxy", "basics", "Proxy basics");
-       ctrl_radiobuttons(s, "Proxy type:", NO_SHORTCUT, 4,
+       s = ctrl_getset(b, "Connection/Proxy", "basics", NULL);
+       ctrl_radiobuttons(s, "Proxy type:", 't', 3,
                          HELPCTX(proxy_type),
                          dlg_stdradiobutton_handler,
                          I(offsetof(Config, proxy_type)),
-                         "None", 'n', I(PROXY_NONE),
-                         "HTTP", 't', I(PROXY_HTTP),
-                         "SOCKS", 's', I(PROXY_SOCKS),
-                         "Telnet", 'l', I(PROXY_TELNET),
+                         "None", I(PROXY_NONE),
+                         "SOCKS 4", I(PROXY_SOCKS4),
+                         "SOCKS 5", I(PROXY_SOCKS5),
+                         "HTTP", I(PROXY_HTTP),
+                         "Telnet", I(PROXY_TELNET),
                          NULL);
        ctrl_columns(s, 2, 80, 20);
        c = ctrl_editbox(s, "Proxy hostname", 'y', 100,
@@ -1314,19 +1456,11 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
                         I(offsetof(Config,proxy_password)),
                         I(sizeof(((Config *)0)->proxy_password)));
        c->editbox.password = 1;
-
-       s = ctrl_getset(b, "Connection/Proxy", "misc",
-                       "Miscellaneous proxy settings");
        ctrl_editbox(s, "Telnet command", 'm', 100,
                     HELPCTX(proxy_command),
                     dlg_stdeditbox_handler,
                     I(offsetof(Config,proxy_telnet_command)),
                     I(sizeof(((Config *)0)->proxy_telnet_command)));
-       ctrl_radiobuttons(s, "SOCKS Version", 'v', 2,
-                         HELPCTX(proxy_socksver),
-                         dlg_stdradiobutton_handler,
-                         I(offsetof(Config, proxy_socks_version)),
-                         "Version 5", I(5), "Version 4", I(4), NULL);
     }
 
     /*
@@ -1340,44 +1474,6 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
        ctrl_settitle(b, "Connection/Telnet",
                      "Options controlling Telnet connections");
 
-       if (!midsession) {
-           s = ctrl_getset(b, "Connection/Telnet", "data",
-                           "Data to send to the server");
-           ctrl_editbox(s, "Terminal-speed string", 's', 50,
-                        HELPCTX(telnet_termspeed),
-                        dlg_stdeditbox_handler, I(offsetof(Config,termspeed)),
-                        I(sizeof(((Config *)0)->termspeed)));
-           ctrl_text(s, "Environment variables:", HELPCTX(telnet_environ));
-           ctrl_columns(s, 2, 80, 20);
-           ed = (struct environ_data *)
-               ctrl_alloc(b, sizeof(struct environ_data));
-           ed->varbox = ctrl_editbox(s, "Variable", 'v', 60,
-                                     HELPCTX(telnet_environ),
-                                     environ_handler, P(ed), P(NULL));
-           ed->varbox->generic.column = 0;
-           ed->valbox = ctrl_editbox(s, "Value", 'l', 60,
-                                     HELPCTX(telnet_environ),
-                                     environ_handler, P(ed), P(NULL));
-           ed->valbox->generic.column = 0;
-           ed->addbutton = ctrl_pushbutton(s, "Add", 'd',
-                                           HELPCTX(telnet_environ),
-                                           environ_handler, P(ed));
-           ed->addbutton->generic.column = 1;
-           ed->rembutton = ctrl_pushbutton(s, "Remove", 'r',
-                                           HELPCTX(telnet_environ),
-                                           environ_handler, P(ed));
-           ed->rembutton->generic.column = 1;
-           ctrl_columns(s, 1, 100);
-           ed->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
-                                      HELPCTX(telnet_environ),
-                                      environ_handler, P(ed));
-           ed->listbox->listbox.height = 3;
-           ed->listbox->listbox.ncols = 2;
-           ed->listbox->listbox.percentages = snewn(2, int);
-           ed->listbox->listbox.percentages[0] = 30;
-           ed->listbox->listbox.percentages[1] = 70;
-       }
-
        s = ctrl_getset(b, "Connection/Telnet", "protocol",
                        "Telnet protocol adjustments");
 
@@ -1395,12 +1491,12 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
                              I(offsetof(Config, passive_telnet)),
                              "Passive", I(1), "Active", I(0), NULL);
        }
-       ctrl_checkbox(s, "Keyboard sends telnet Backspace and Interrupt", 'k',
+       ctrl_checkbox(s, "Keyboard sends Telnet special commands", 'k',
                      HELPCTX(telnet_specialkeys),
                      dlg_stdcheckbox_handler,
                      I(offsetof(Config,telnet_keyboard)));
-       ctrl_checkbox(s, "Return key sends telnet New Line instead of ^M",
-                     NO_SHORTCUT, HELPCTX(telnet_newline),
+       ctrl_checkbox(s, "Return key sends Telnet New Line instead of ^M",
+                     'm', HELPCTX(telnet_newline),
                      dlg_stdcheckbox_handler,
                      I(offsetof(Config,telnet_newline)));
     }
@@ -1415,10 +1511,6 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
 
        s = ctrl_getset(b, "Connection/Rlogin", "data",
                        "Data to send to the server");
-       ctrl_editbox(s, "Terminal-speed string", 's', 50,
-                    HELPCTX(rlogin_termspeed),
-                    dlg_stdeditbox_handler, I(offsetof(Config,termspeed)),
-                    I(sizeof(((Config *)0)->termspeed)));
        ctrl_editbox(s, "Local username:", 'l', 50,
                     HELPCTX(rlogin_localuser),
                     dlg_stdeditbox_handler, I(offsetof(Config,localusername)),
@@ -1427,10 +1519,11 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
     }
 
     /*
-     * All the SSH stuff is omitted in PuTTYtel.
+     * All the SSH stuff is omitted in PuTTYtel, or in a reconfig
+     * when we're not doing SSH.
      */
 
-    if (!midsession && backends[3].name != NULL) {
+    if (backends[3].name != NULL && (!midsession || protocol == PROT_SSH)) {
 
        /*
         * The Connection/SSH panel.
@@ -1438,93 +1531,146 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
        ctrl_settitle(b, "Connection/SSH",
                      "Options controlling SSH connections");
 
-       s = ctrl_getset(b, "Connection/SSH", "data",
-                       "Data to send to the server");
-       ctrl_editbox(s, "Remote command:", 'r', 100,
-                    HELPCTX(ssh_command),
-                    dlg_stdeditbox_handler, I(offsetof(Config,remote_cmd)),
-                    I(sizeof(((Config *)0)->remote_cmd)));
-
-       s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
-       ctrl_checkbox(s, "Don't allocate a pseudo-terminal", 'p',
-                     HELPCTX(ssh_nopty),
-                     dlg_stdcheckbox_handler,
-                     I(offsetof(Config,nopty)));
-       ctrl_checkbox(s, "Enable compression", 'e',
-                     HELPCTX(ssh_compress),
-                     dlg_stdcheckbox_handler,
-                     I(offsetof(Config,compression)));
-       ctrl_radiobuttons(s, "Preferred SSH protocol version:", NO_SHORTCUT, 4,
-                         HELPCTX(ssh_protocol),
-                         dlg_stdradiobutton_handler,
-                         I(offsetof(Config, sshprot)),
-                         "1 only", 'l', I(0),
-                         "1", '1', I(1),
-                         "2", '2', I(2),
-                         "2 only", 'n', I(3), NULL);
-
-       s = ctrl_getset(b, "Connection/SSH", "encryption", "Encryption options");
-       c = ctrl_draglist(s, "Encryption cipher selection policy:", 's',
+       if (midsession) {
+           s = ctrl_getset(b, "Connection/SSH", "disclaimer", NULL);
+           ctrl_text(s, "Nothing on this panel may be reconfigured in mid-"
+                     "session; it is only here so that sub-panels of it can "
+                     "exist without looking strange.", HELPCTX(no_help));
+       }
+
+       if (!midsession) {
+
+           s = ctrl_getset(b, "Connection/SSH", "data",
+                           "Data to send to the server");
+           ctrl_editbox(s, "Remote command:", 'r', 100,
+                        HELPCTX(ssh_command),
+                        dlg_stdeditbox_handler, I(offsetof(Config,remote_cmd)),
+                        I(sizeof(((Config *)0)->remote_cmd)));
+
+           s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
+           ctrl_checkbox(s, "Don't allocate a pseudo-terminal", 'p',
+                         HELPCTX(ssh_nopty),
+                         dlg_stdcheckbox_handler,
+                         I(offsetof(Config,nopty)));
+           ctrl_checkbox(s, "Don't start a shell or command at all", 'n',
+                         HELPCTX(ssh_noshell),
+                         dlg_stdcheckbox_handler,
+                         I(offsetof(Config,ssh_no_shell)));
+           ctrl_checkbox(s, "Enable compression", 'e',
+                         HELPCTX(ssh_compress),
+                         dlg_stdcheckbox_handler,
+                         I(offsetof(Config,compression)));
+           ctrl_radiobuttons(s, "Preferred SSH protocol version:", NO_SHORTCUT, 4,
+                             HELPCTX(ssh_protocol),
+                             dlg_stdradiobutton_handler,
+                             I(offsetof(Config, sshprot)),
+                             "1 only", 'l', I(0),
+                             "1", '1', I(1),
+                             "2", '2', I(2),
+                             "2 only", 'y', I(3), NULL);
+
+           s = ctrl_getset(b, "Connection/SSH", "encryption", "Encryption options");
+           c = ctrl_draglist(s, "Encryption cipher selection policy:", 's',
+                             HELPCTX(ssh_ciphers),
+                             cipherlist_handler, P(NULL));
+           c->listbox.height = 6;
+
+           ctrl_checkbox(s, "Enable legacy use of single-DES in SSH 2", 'i',
                          HELPCTX(ssh_ciphers),
-                         cipherlist_handler, P(NULL));
-       c->listbox.height = 6;
-       
-       ctrl_checkbox(s, "Enable non-standard use of single-DES in SSH 2", 'i',
-                     HELPCTX(ssh_ciphers),
-                     dlg_stdcheckbox_handler,
-                     I(offsetof(Config,ssh2_des_cbc)));
+                         dlg_stdcheckbox_handler,
+                         I(offsetof(Config,ssh2_des_cbc)));
+       }
 
        /*
-        * The Connection/SSH/Auth panel.
+        * The Connection/SSH/Kex panel. (Owing to repeat key
+        * exchange, this is all meaningful in mid-session _if_
+        * we're using SSH2 or haven't decided yet.)
         */
-       ctrl_settitle(b, "Connection/SSH/Auth",
-                     "Options controlling SSH authentication");
+       if (protcfginfo != 1) {
+           ctrl_settitle(b, "Connection/SSH/Kex",
+                         "Options controlling SSH key exchange");
+
+           s = ctrl_getset(b, "Connection/SSH/Kex", "main",
+                           "Key exchange algorithm options");
+           c = ctrl_draglist(s, "Algorithm selection policy", 's',
+                             HELPCTX(ssh_kexlist),
+                             kexlist_handler, P(NULL));
+           c->listbox.height = 5;
+
+           s = ctrl_getset(b, "Connection/SSH/Kex", "repeat",
+                           "Options controlling key re-exchange");
+
+           ctrl_editbox(s, "Max minutes before rekey (0 for no limit)", 't', 20,
+                        HELPCTX(ssh_kex_repeat),
+                        dlg_stdeditbox_handler,
+                        I(offsetof(Config,ssh_rekey_time)),
+                        I(-1));
+           ctrl_editbox(s, "Max data before rekey (0 for no limit)", 'x', 20,
+                        HELPCTX(ssh_kex_repeat),
+                        dlg_stdeditbox_handler,
+                        I(offsetof(Config,ssh_rekey_data)),
+                        I(16));
+           ctrl_text(s, "(Use 1M for 1 megabyte, 1G for 1 gigabyte etc)",
+                     HELPCTX(ssh_kex_repeat));
+       }
 
-       s = ctrl_getset(b, "Connection/SSH/Auth", "methods",
-                       "Authentication methods");
-       ctrl_checkbox(s, "Attempt TIS or CryptoCard auth (SSH1)", 'm',
-                     HELPCTX(ssh_auth_tis),
-                     dlg_stdcheckbox_handler,
-                     I(offsetof(Config,try_tis_auth)));
-       ctrl_checkbox(s, "Attempt \"keyboard-interactive\" auth (SSH2)",
-                     'i', HELPCTX(ssh_auth_ki),
-                     dlg_stdcheckbox_handler,
-                     I(offsetof(Config,try_ki_auth)));
-
-       s = ctrl_getset(b, "Connection/SSH/Auth", "params",
-                       "Authentication parameters");
-       ctrl_checkbox(s, "Allow agent forwarding", 'f',
-                     HELPCTX(ssh_auth_agentfwd),
-                     dlg_stdcheckbox_handler, I(offsetof(Config,agentfwd)));
-       ctrl_checkbox(s, "Allow attempted changes of username in SSH2", 'u',
-                     HELPCTX(ssh_auth_changeuser),
-                     dlg_stdcheckbox_handler,
-                     I(offsetof(Config,change_username)));
-       ctrl_filesel(s, "Private key file for authentication:", 'k',
-                    FILTER_KEY_FILES, FALSE, "Select private key file",
-                    HELPCTX(ssh_auth_privkey),
-                    dlg_stdfilesel_handler, I(offsetof(Config, keyfile)));
+       if (!midsession) {
+
+           /*
+            * The Connection/SSH/Auth panel.
+            */
+           ctrl_settitle(b, "Connection/SSH/Auth",
+                         "Options controlling SSH authentication");
+
+           s = ctrl_getset(b, "Connection/SSH/Auth", "methods",
+                           "Authentication methods");
+           ctrl_checkbox(s, "Attempt TIS or CryptoCard auth (SSH1)", 'm',
+                         HELPCTX(ssh_auth_tis),
+                         dlg_stdcheckbox_handler,
+                         I(offsetof(Config,try_tis_auth)));
+           ctrl_checkbox(s, "Attempt \"keyboard-interactive\" auth (SSH2)",
+                         'i', HELPCTX(ssh_auth_ki),
+                         dlg_stdcheckbox_handler,
+                         I(offsetof(Config,try_ki_auth)));
+
+           s = ctrl_getset(b, "Connection/SSH/Auth", "params",
+                           "Authentication parameters");
+           ctrl_checkbox(s, "Allow agent forwarding", 'f',
+                         HELPCTX(ssh_auth_agentfwd),
+                         dlg_stdcheckbox_handler, I(offsetof(Config,agentfwd)));
+           ctrl_checkbox(s, "Allow attempted changes of username in SSH2", 'u',
+                         HELPCTX(ssh_auth_changeuser),
+                         dlg_stdcheckbox_handler,
+                         I(offsetof(Config,change_username)));
+           ctrl_filesel(s, "Private key file for authentication:", 'k',
+                        FILTER_KEY_FILES, FALSE, "Select private key file",
+                        HELPCTX(ssh_auth_privkey),
+                        dlg_stdfilesel_handler, I(offsetof(Config, keyfile)));
+       }
 
        /*
-        * The Connection/SSH/Tunnels panel.
+        * The Connection/SSH/Tunnels panel. Some of this _is_
+        * still available in mid-session.
         */
        ctrl_settitle(b, "Connection/SSH/Tunnels",
                      "Options controlling SSH tunnelling");
 
-       s = ctrl_getset(b, "Connection/SSH/Tunnels", "x11", "X11 forwarding");
-       ctrl_checkbox(s, "Enable X11 forwarding", 'e',
-                     HELPCTX(ssh_tunnels_x11),
-                     dlg_stdcheckbox_handler,I(offsetof(Config,x11_forward)));
-       ctrl_editbox(s, "X display location", 'x', 50,
-                    HELPCTX(ssh_tunnels_x11),
-                    dlg_stdeditbox_handler, I(offsetof(Config,x11_display)),
-                    I(sizeof(((Config *)0)->x11_display)));
-       ctrl_radiobuttons(s, "Remote X11 authentication protocol", 'u', 2,
-                         HELPCTX(ssh_tunnels_x11auth),
-                         dlg_stdradiobutton_handler,
-                         I(offsetof(Config, x11_auth)),
-                         "MIT-Magic-Cookie-1", I(X11_MIT),
-                         "XDM-Authorization-1", I(X11_XDM), NULL);
+       if (!midsession) {
+           s = ctrl_getset(b, "Connection/SSH/Tunnels", "x11", "X11 forwarding");
+           ctrl_checkbox(s, "Enable X11 forwarding", 'e',
+                         HELPCTX(ssh_tunnels_x11),
+                         dlg_stdcheckbox_handler,I(offsetof(Config,x11_forward)));
+           ctrl_editbox(s, "X display location", 'x', 50,
+                        HELPCTX(ssh_tunnels_x11),
+                        dlg_stdeditbox_handler, I(offsetof(Config,x11_display)),
+                        I(sizeof(((Config *)0)->x11_display)));
+           ctrl_radiobuttons(s, "Remote X11 authentication protocol", 'u', 2,
+                             HELPCTX(ssh_tunnels_x11auth),
+                             dlg_stdradiobutton_handler,
+                             I(offsetof(Config, x11_auth)),
+                             "MIT-Magic-Cookie-1", I(X11_MIT),
+                             "XDM-Authorization-1", I(X11_XDM), NULL);
+       }
 
        s = ctrl_getset(b, "Connection/SSH/Tunnels", "portfwd",
                        "Port forwarding");
@@ -1582,37 +1728,36 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
        ctrl_tabdelay(s, pfd->addbutton);
        ctrl_columns(s, 1, 100);
 
-       /*
-        * The Connection/SSH/Bugs panel.
-        */
-       ctrl_settitle(b, "Connection/SSH/Bugs",
-                     "Workarounds for SSH server bugs");
-
-       s = ctrl_getset(b, "Connection/SSH/Bugs", "main",
-                       "Detection of known bugs in SSH servers");
-       ctrl_droplist(s, "Chokes on SSH1 ignore messages", 'i', 20,
-                     HELPCTX(ssh_bugs_ignore1),
-                     sshbug_handler, I(offsetof(Config,sshbug_ignore1)));
-       ctrl_droplist(s, "Refuses all SSH1 password camouflage", 's', 20,
-                     HELPCTX(ssh_bugs_plainpw1),
-                     sshbug_handler, I(offsetof(Config,sshbug_plainpw1)));
-       ctrl_droplist(s, "Chokes on SSH1 RSA authentication", 'r', 20,
-                     HELPCTX(ssh_bugs_rsa1),
-                     sshbug_handler, I(offsetof(Config,sshbug_rsa1)));
-       ctrl_droplist(s, "Miscomputes SSH2 HMAC keys", 'm', 20,
-                     HELPCTX(ssh_bugs_hmac2),
-                     sshbug_handler, I(offsetof(Config,sshbug_hmac2)));
-       ctrl_droplist(s, "Miscomputes SSH2 encryption keys", 'e', 20,
-                     HELPCTX(ssh_bugs_derivekey2),
-                     sshbug_handler, I(offsetof(Config,sshbug_derivekey2)));
-       ctrl_droplist(s, "Requires padding on SSH2 RSA signatures", 'p', 20,
-                     HELPCTX(ssh_bugs_rsapad2),
-                     sshbug_handler, I(offsetof(Config,sshbug_rsapad2)));
-       ctrl_droplist(s, "Chokes on Diffie-Hellman group exchange", 'd', 20,
-                     HELPCTX(ssh_bugs_dhgex2),
-                     sshbug_handler, I(offsetof(Config,sshbug_dhgex2)));
-       ctrl_droplist(s, "Misuses the session ID in PK auth", 'n', 20,
-                     HELPCTX(ssh_bugs_pksessid2),
-                     sshbug_handler, I(offsetof(Config,sshbug_pksessid2)));
+       if (!midsession) {
+           /*
+            * The Connection/SSH/Bugs panel.
+            */
+           ctrl_settitle(b, "Connection/SSH/Bugs",
+                         "Workarounds for SSH server bugs");
+
+           s = ctrl_getset(b, "Connection/SSH/Bugs", "main",
+                           "Detection of known bugs in SSH servers");
+           ctrl_droplist(s, "Chokes on SSH1 ignore messages", 'i', 20,
+                         HELPCTX(ssh_bugs_ignore1),
+                         sshbug_handler, I(offsetof(Config,sshbug_ignore1)));
+           ctrl_droplist(s, "Refuses all SSH1 password camouflage", 's', 20,
+                         HELPCTX(ssh_bugs_plainpw1),
+                         sshbug_handler, I(offsetof(Config,sshbug_plainpw1)));
+           ctrl_droplist(s, "Chokes on SSH1 RSA authentication", 'r', 20,
+                         HELPCTX(ssh_bugs_rsa1),
+                         sshbug_handler, I(offsetof(Config,sshbug_rsa1)));
+           ctrl_droplist(s, "Miscomputes SSH2 HMAC keys", 'm', 20,
+                         HELPCTX(ssh_bugs_hmac2),
+                         sshbug_handler, I(offsetof(Config,sshbug_hmac2)));
+           ctrl_droplist(s, "Miscomputes SSH2 encryption keys", 'e', 20,
+                         HELPCTX(ssh_bugs_derivekey2),
+                         sshbug_handler, I(offsetof(Config,sshbug_derivekey2)));
+           ctrl_droplist(s, "Requires padding on SSH2 RSA signatures", 'p', 20,
+                         HELPCTX(ssh_bugs_rsapad2),
+                         sshbug_handler, I(offsetof(Config,sshbug_rsapad2)));
+           ctrl_droplist(s, "Misuses the session ID in PK auth", 'n', 20,
+                         HELPCTX(ssh_bugs_pksessid2),
+                         sshbug_handler, I(offsetof(Config,sshbug_pksessid2)));
+       }
     }
 }