X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/62697e04c392ebc56148c4037b79a00dadc777cb..055817455466c8eb60392f30bb7c689763962e17:/config.c diff --git a/config.c b/config.c index 841c0e6a..e269e1f8 100644 --- a/config.c +++ b/config.c @@ -110,7 +110,7 @@ static void cipherlist_handler(union control *ctrl, void *dlg, break; } } - dlg_listbox_addwithindex(ctrl, dlg, cstr, c); + dlg_listbox_addwithid(ctrl, dlg, cstr, c); } dlg_update_done(ctrl, dlg); @@ -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) { @@ -133,12 +175,18 @@ static void printerbox_handler(union control *ctrl, void *dlg, printer_enum *pe; dlg_update_start(ctrl, dlg); - dlg_listbox_clear(ctrl, dlg); - dlg_listbox_add(ctrl, dlg, PRINTER_DISABLED_STRING); - pe = printer_start_enum(&nprinters); - for (i = 0; i < nprinters; i++) - dlg_listbox_add(ctrl, dlg, printer_get_name(pe, i)); - printer_finish_enum(pe); + /* + * Some backends may wish to disable the drop-down list on + * this edit box. Be prepared for this. + */ + if (ctrl->editbox.has_list) { + dlg_listbox_clear(ctrl, dlg); + dlg_listbox_add(ctrl, dlg, PRINTER_DISABLED_STRING); + pe = printer_start_enum(&nprinters); + for (i = 0; i < nprinters; i++) + dlg_listbox_add(ctrl, dlg, printer_get_name(pe, i)); + printer_finish_enum(pe); + } dlg_editbox_set(ctrl, dlg, (*cfg->printer ? cfg->printer : PRINTER_DISABLED_STRING)); @@ -156,7 +204,7 @@ static void codepage_handler(union control *ctrl, void *dlg, Config *cfg = (Config *)data; if (event == EVENT_REFRESH) { int i; - char *cp; + const char *cp; dlg_update_start(ctrl, dlg); strcpy(cfg->line_codepage, cp_name(decode_codepage(cfg->line_codepage))); @@ -179,9 +227,9 @@ static void sshbug_handler(union control *ctrl, void *dlg, if (event == EVENT_REFRESH) { dlg_update_start(ctrl, dlg); dlg_listbox_clear(ctrl, dlg); - dlg_listbox_addwithindex(ctrl, dlg, "Auto", AUTO); - dlg_listbox_addwithindex(ctrl, dlg, "Off", FORCE_OFF); - dlg_listbox_addwithindex(ctrl, dlg, "On", FORCE_ON); + dlg_listbox_addwithid(ctrl, dlg, "Auto", AUTO); + dlg_listbox_addwithid(ctrl, dlg, "Off", FORCE_OFF); + dlg_listbox_addwithid(ctrl, dlg, "On", FORCE_ON); switch (*(int *)ATOFFSET(data, ctrl->listbox.context.i)) { case AUTO: dlg_listbox_select(ctrl, dlg, 0); break; case FORCE_OFF: dlg_listbox_select(ctrl, dlg, 1); break; @@ -204,6 +252,7 @@ struct sessionsaver_data { union control *editbox, *listbox, *loadbutton, *savebutton, *delbutton; union control *okbutton, *cancelbutton; struct sesslist *sesslist; + int midsession; }; /* @@ -251,7 +300,9 @@ static void sessionsaver_handler(union control *ctrl, void *dlg, * session edit box (since it must persist even when we switch * panels, but is not part of the Config). */ - 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'; @@ -276,7 +327,9 @@ static void sessionsaver_handler(union control *ctrl, void *dlg, SAVEDSESSION_LEN); } } else if (event == EVENT_ACTION) { - if (ctrl == ssd->listbox || ctrl == ssd->loadbutton) { + if (!ssd->midsession && + (ctrl == ssd->listbox || + (ssd->loadbutton && ctrl == ssd->loadbutton))) { /* * The user has double-clicked a session, or hit Load. * We must load the selected session, and then @@ -305,12 +358,19 @@ static void sessionsaver_handler(union control *ctrl, void *dlg, savedsession[0] = '\0'; } } - save_settings(savedsession, !isdef, cfg); + { + char *errmsg = save_settings(savedsession, !isdef, cfg); + if (errmsg) { + dlg_error_msg(dlg, errmsg); + sfree(errmsg); + } + } get_sesslist(ssd->sesslist, FALSE); get_sesslist(ssd->sesslist, TRUE); dlg_refresh(ssd->editbox, dlg); dlg_refresh(ssd->listbox, dlg); - } else if (ctrl == ssd->delbutton) { + } else if (!ssd->midsession && + ssd->delbutton && ctrl == ssd->delbutton) { int i = dlg_listbox_index(ssd->listbox, dlg); if (i <= 0) { dlg_beep(dlg); @@ -321,6 +381,11 @@ static void sessionsaver_handler(union control *ctrl, void *dlg, dlg_refresh(ssd->listbox, dlg); } } else if (ctrl == ssd->okbutton) { + if (ssd->midsession) { + /* 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_ @@ -328,7 +393,7 @@ static void sessionsaver_handler(union control *ctrl, void *dlg, * there was a session selected in that which had a * valid host name in it, then load it and go. */ - if (dlg_last_focused(dlg) == ssd->listbox && !*cfg->host) { + if (dlg_last_focused(ctrl, dlg) == ssd->listbox && !*cfg->host) { Config cfg2; if (!load_selected_session(ssd, savedsession, dlg, &cfg2)) { dlg_beep(dlg); @@ -337,9 +402,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; } /* @@ -396,7 +463,7 @@ static void charclass_handler(union control *ctrl, void *dlg, } struct colour_data { - union control *listbox, *rgbtext, *button; + union control *listbox, *redit, *gedit, *bedit, *button; }; static const char *const colours[] = { @@ -429,7 +496,9 @@ static void colour_handler(union control *ctrl, void *dlg, for (i = 0; i < lenof(colours); i++) dlg_listbox_add(ctrl, dlg, colours[i]); dlg_update_done(ctrl, dlg); - dlg_text_set(cd->rgbtext, dlg, ""); + dlg_editbox_set(cd->redit, dlg, ""); + dlg_editbox_set(cd->gedit, dlg, ""); + dlg_editbox_set(cd->bedit, dlg, ""); } } else if (event == EVENT_SELCHANGE) { if (ctrl == cd->listbox) { @@ -444,6 +513,25 @@ static void colour_handler(union control *ctrl, void *dlg, b = cfg->colours[i][2]; update = TRUE; } + } else if (event == EVENT_VALCHANGE) { + if (ctrl == cd->redit || ctrl == cd->gedit || ctrl == cd->bedit) { + /* The user has changed the colour using the edit boxes. */ + char buf[80]; + int i, cval; + + dlg_editbox_get(ctrl, dlg, buf, lenof(buf)); + cval = atoi(buf) & 255; + + i = dlg_listbox_index(cd->listbox, dlg); + if (i >= 0) { + if (ctrl == cd->redit) + cfg->colours[i][0] = cval; + else if (ctrl == cd->gedit) + cfg->colours[i][1] = cval; + else if (ctrl == cd->bedit) + cfg->colours[i][2] = cval; + } + } } else if (event == EVENT_ACTION) { if (ctrl == cd->button) { int i = dlg_listbox_index(cd->listbox, dlg); @@ -480,8 +568,9 @@ static void colour_handler(union control *ctrl, void *dlg, if (update) { char buf[40]; - sprintf(buf, "%02x/%02x/%02x", r, g, b); - dlg_text_set(cd->rgbtext, dlg, buf); + sprintf(buf, "%d", r); dlg_editbox_set(cd->redit, dlg, buf); + sprintf(buf, "%d", g); dlg_editbox_set(cd->gedit, dlg, buf); + sprintf(buf, "%d", b); dlg_editbox_set(cd->bedit, dlg, buf); } } @@ -577,6 +666,7 @@ static void environ_handler(union control *ctrl, void *dlg, struct portfwd_data { union control *addbutton, *rembutton, *listbox; union control *sourcebox, *destbox, *direction; + union control *addressfamily; }; static void portfwd_handler(union control *ctrl, void *dlg, @@ -596,29 +686,55 @@ static void portfwd_handler(union control *ctrl, void *dlg, p += strlen(p) + 1; } dlg_update_done(ctrl, dlg); + } else if (ctrl == pfd->direction) { + /* + * Default is Local. + */ + dlg_radiobutton_set(ctrl, dlg, 0); + } else if (ctrl == pfd->addressfamily) { + dlg_radiobutton_set(ctrl, dlg, 0); } } else if (event == EVENT_ACTION) { if (ctrl == pfd->addbutton) { char str[sizeof(cfg->portfwd)]; char *p; - if (dlg_radiobutton_get(pfd->direction, dlg) == 0) - str[0] = 'L'; + int i, type; + int whichbutton; + + i = 0; + whichbutton = dlg_radiobutton_get(pfd->addressfamily, dlg); + if (whichbutton == 1) + str[i++] = '4'; + else if (whichbutton == 2) + str[i++] = '6'; + + whichbutton = dlg_radiobutton_get(pfd->direction, dlg); + if (whichbutton == 0) + type = 'L'; + else if (whichbutton == 1) + type = 'R'; else - str[0] = 'R'; - dlg_editbox_get(pfd->sourcebox, dlg, str+1, sizeof(str) - 2); - if (!str[1]) { + type = 'D'; + str[i++] = type; + + dlg_editbox_get(pfd->sourcebox, dlg, str+i, sizeof(str) - i); + if (!str[2]) { dlg_error_msg(dlg, "You need to specify a source port number"); return; } p = str + strlen(str); - *p++ = '\t'; - dlg_editbox_get(pfd->destbox, dlg, p, sizeof(str)-1 - (p - str)); - if (!*p || !strchr(p, ':')) { - dlg_error_msg(dlg, - "You need to specify a destination address\n" - "in the form \"host.name:port\""); - return; - } + if (type != 'D') { + *p++ = '\t'; + dlg_editbox_get(pfd->destbox, dlg, p, + sizeof(str)-1 - (p - str)); + if (!*p || !strchr(p, ':')) { + dlg_error_msg(dlg, + "You need to specify a destination address\n" + "in the form \"host.name:port\""); + return; + } + } else + *p = '\0'; p = cfg->portfwd; while (*p) { while (*p) @@ -671,7 +787,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; @@ -680,10 +796,12 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist, struct environ_data *ed; struct portfwd_data *pfd; union control *c; + char *str; ssd = (struct sessionsaver_data *) ctrl_alloc(b, sizeof(struct sessionsaver_data)); - ssd->sesslist = (midsession ? NULL : sesslist); + memset(ssd, 0, sizeof(*ssd)); + ssd->midsession = midsession; /* * The standard panel that appears at the bottom of all panels: @@ -700,6 +818,7 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist, ssd->okbutton->generic.column = 3; ssd->cancelbutton = ctrl_pushbutton(s, "Cancel", 'c', HELPCTX(no_help), sessionsaver_handler, P(ssd)); + ssd->cancelbutton->button.iscancel = TRUE; ssd->cancelbutton->generic.column = 4; /* We carefully don't close the 5-column part, so that platform- * specific add-ons can put extra buttons alongside Open and Cancel. */ @@ -707,7 +826,9 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist, /* * The Session panel. */ - ctrl_settitle(b, "Session", "Basic options for your PuTTY session"); + str = dupprintf("Basic options for your %s session", appname); + ctrl_settitle(b, "Session", str); + sfree(str); if (!midsession) { s = ctrl_getset(b, "Session", "hostport", @@ -741,38 +862,55 @@ 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); + /* + * 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; + if (!midsession) { 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; + } else { + /* We can't offer the Load button mid-session, as it would allow the + * user to load and subsequently save settings they can't see. (And + * also change otherwise immutable settings underfoot; that probably + * shouldn't be a problem, but.) */ + ssd->loadbutton = NULL; + } + /* "Save" button is permitted mid-session. */ + ssd->savebutton = ctrl_pushbutton(s, "Save", 'v', + HELPCTX(session_saved), + sessionsaver_handler, P(ssd)); + ssd->savebutton->generic.column = 1; + if (!midsession) { ssd->delbutton = ctrl_pushbutton(s, "Delete", 'd', HELPCTX(session_saved), sessionsaver_handler, P(ssd)); ssd->delbutton->generic.column = 1; - 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; - ctrl_columns(s, 1, 100); + } else { + /* Disable the Delete button mid-session too, for UI consistency. */ + ssd->delbutton = NULL; } + ctrl_columns(s, 1, 100); s = ctrl_getset(b, "Session", "otheropts", NULL); c = ctrl_radiobuttons(s, "Close window on exit:", 'w', 4, @@ -789,14 +927,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), @@ -810,6 +961,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. @@ -954,17 +1120,28 @@ 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. */ - ctrl_settitle(b, "Window", "Options controlling PuTTY's window"); + str = dupprintf("Options controlling %s's window", appname); + ctrl_settitle(b, "Window", str); + sfree(str); s = ctrl_getset(b, "Window", "size", "Set the size of the window"); ctrl_columns(s, 2, 50, 50); @@ -1000,8 +1177,9 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist, /* * The Window/Appearance panel. */ - ctrl_settitle(b, "Window/Appearance", - "Configure the appearance of PuTTY's window"); + str = dupprintf("Configure the appearance of %s's window", appname); + ctrl_settitle(b, "Window/Appearance", str); + sfree(str); s = ctrl_getset(b, "Window/Appearance", "cursor", "Adjust the use of the cursor"); @@ -1038,8 +1216,9 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist, /* * The Window/Behaviour panel. */ - ctrl_settitle(b, "Window/Behaviour", - "Configure the behaviour of PuTTY's window"); + str = dupprintf("Configure the behaviour of %s's window", appname); + ctrl_settitle(b, "Window/Behaviour", str); + sfree(str); s = ctrl_getset(b, "Window/Behaviour", "title", "Adjust the behaviour of the window title"); @@ -1069,26 +1248,24 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist, 'r', 100, HELPCTX(translation_codepage), codepage_handler, P(NULL), P(NULL)); - s = ctrl_getset(b, "Window/Translation", "linedraw", - "Adjust how PuTTY displays line drawing characters"); + 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"); @@ -1113,7 +1290,7 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist, charclass_handler, P(ccd)); ccd->listbox->listbox.multisel = 1; ccd->listbox->listbox.ncols = 4; - ccd->listbox->listbox.percentages = smalloc(4*sizeof(int)); + ccd->listbox->listbox.percentages = snewn(4, int); ccd->listbox->listbox.percentages[0] = 15; ccd->listbox->listbox.percentages[1] = 25; ccd->listbox->listbox.percentages[2] = 20; @@ -1136,12 +1313,19 @@ 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))); - s = ctrl_getset(b, "Window/Colours", "adjust", - "Adjust the precise colours PuTTY displays"); + str = dupprintf("Adjust the precise colours %s displays", appname); + s = ctrl_getset(b, "Window/Colours", "adjust", str); + sfree(str); ctrl_text(s, "Select a colour from the list, and then click the" " Modify button to change its appearance.", HELPCTX(colours_config)); @@ -1150,46 +1334,125 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist, cd->listbox = ctrl_listbox(s, "Select a colour to adjust:", 'u', HELPCTX(colours_config), colour_handler, P(cd)); cd->listbox->generic.column = 0; + cd->listbox->listbox.height = 7; c = ctrl_text(s, "RGB value:", HELPCTX(colours_config)); c->generic.column = 1; - cd->rgbtext = ctrl_text(s, "00/00/00", HELPCTX(colours_config)); - cd->rgbtext->generic.column = 1; + cd->redit = ctrl_editbox(s, "Red", 'r', 50, HELPCTX(colours_config), + colour_handler, P(cd), P(NULL)); + cd->redit->generic.column = 1; + cd->gedit = ctrl_editbox(s, "Green", 'n', 50, HELPCTX(colours_config), + colour_handler, P(cd), P(NULL)); + cd->gedit->generic.column = 1; + cd->bedit = ctrl_editbox(s, "Blue", 'e', 50, HELPCTX(colours_config), + colour_handler, P(cd), P(NULL)); + cd->bedit->generic.column = 1; cd->button = ctrl_pushbutton(s, "Modify", 'm', HELPCTX(colours_config), colour_handler, P(cd)); cd->button->generic.column = 1; 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))); - } + 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))); + s = ctrl_getset(b, "Connection", "ipversion", + "Internet protocol version"); + ctrl_radiobuttons(s, NULL, NO_SHORTCUT, +#ifndef NO_IPV6 + 3, +#else + 2, +#endif + HELPCTX(connection_ipversion), + dlg_stdradiobutton_handler, + I(offsetof(Config, addressfamily)), + "Auto", NO_SHORTCUT, I(ADDRTYPE_UNSPEC), + "IPv4", NO_SHORTCUT, I(ADDRTYPE_IPV4), +#ifndef NO_IPV6 + "IPv6", NO_SHORTCUT, I(ADDRTYPE_IPV6), +#endif + NULL); + } + + /* + * A sub-panel Connection/Data, containing options that + * decide on data to send to the server. + */ + if (!midsession) { + ctrl_settitle(b, "Connection/Data", "Data to send to the server"); + + s = ctrl_getset(b, "Connection/Data", "login", + "Login details"); + ctrl_editbox(s, "Auto-login username", 'u', 50, + HELPCTX(connection_username), + dlg_stdeditbox_handler, I(offsetof(Config,username)), + I(sizeof(((Config *)0)->username))); + + s = ctrl_getset(b, "Connection/Data", "term", + "Terminal details"); + 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))); + + s = ctrl_getset(b, "Connection/Data", "env", + "Environment variables"); + 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; + } - 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) { @@ -1199,15 +1462,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, @@ -1250,19 +1514,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); } /* @@ -1276,40 +1532,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; - } - s = ctrl_getset(b, "Connection/Telnet", "protocol", "Telnet protocol adjustments"); @@ -1327,12 +1549,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))); } @@ -1347,10 +1569,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)), @@ -1359,10 +1577,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. @@ -1370,93 +1589,151 @@ 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))); + } + + if (!midsession) { + /* + * The Connection/SSH/X11 panel. + */ + ctrl_settitle(b, "Connection/SSH/X11", + "Options controlling SSH X11 forwarding"); + + s = ctrl_getset(b, "Connection/SSH/X11", "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); + } /* - * The Connection/SSH/Tunnels panel. + * The Tunnels panel _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); + "Options controlling SSH port forwarding"); s = ctrl_getset(b, "Connection/SSH/Tunnels", "portfwd", "Port forwarding"); @@ -1484,6 +1761,10 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist, HELPCTX(ssh_tunnels_portfwd), portfwd_handler, P(pfd)); pfd->listbox->listbox.height = 3; + pfd->listbox->listbox.ncols = 2; + pfd->listbox->listbox.percentages = snewn(2, int); + pfd->listbox->listbox.percentages[0] = 20; + pfd->listbox->listbox.percentages[1] = 80; ctrl_tabdelay(s, pfd->rembutton); ctrl_text(s, "Add new forwarded port:", HELPCTX(ssh_tunnels_portfwd)); /* You want to enter source, destination and type, _then_ hit Add. @@ -1500,45 +1781,61 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist, pfd->destbox = ctrl_editbox(s, "Destination", 'i', 67, HELPCTX(ssh_tunnels_portfwd), portfwd_handler, P(pfd), P(NULL)); - pfd->direction = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 2, + pfd->direction = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3, HELPCTX(ssh_tunnels_portfwd), portfwd_handler, P(pfd), "Local", 'l', P(NULL), - "Remote", 'm', P(NULL), NULL); + "Remote", 'm', P(NULL), + "Dynamic", 'y', P(NULL), + NULL); + pfd->addressfamily = + ctrl_radiobuttons(s, NULL, NO_SHORTCUT, +#ifndef NO_IPV6 + 3, +#else + 2, +#endif + HELPCTX(ssh_tunnels_portfwd_ipversion), + portfwd_handler, P(pfd), + "Auto", NO_SHORTCUT, I(ADDRTYPE_UNSPEC), + "IPv4", NO_SHORTCUT, I(ADDRTYPE_IPV4), +#ifndef NO_IPV6 + "IPv6", NO_SHORTCUT, I(ADDRTYPE_IPV6), +#endif + NULL); 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))); + } } }