2 * config.c - the platform-independent parts of the PuTTY
13 #define PRINTER_DISABLED_STRING "None (printing disabled)"
15 #define HOST_BOX_TITLE "Host Name (or IP address)"
16 #define PORT_BOX_TITLE "Port"
18 void conf_radiobutton_handler(union control *ctrl, void *dlg,
19 void *data, int event)
22 Conf *conf = (Conf *)data;
25 * For a standard radio button set, the context parameter gives
26 * the primary key (CONF_foo), and the extra data per button
27 * gives the value the target field should take if that button
28 * is the one selected.
30 if (event == EVENT_REFRESH) {
31 int val = conf_get_int(conf, ctrl->radio.context.i);
32 for (button = 0; button < ctrl->radio.nbuttons; button++)
33 if (val == ctrl->radio.buttondata[button].i)
35 /* We expected that `break' to happen, in all circumstances. */
36 assert(button < ctrl->radio.nbuttons);
37 dlg_radiobutton_set(ctrl, dlg, button);
38 } else if (event == EVENT_VALCHANGE) {
39 button = dlg_radiobutton_get(ctrl, dlg);
40 assert(button >= 0 && button < ctrl->radio.nbuttons);
41 conf_set_int(conf, ctrl->radio.context.i,
42 ctrl->radio.buttondata[button].i);
46 #define CHECKBOX_INVERT (1<<30)
47 void conf_checkbox_handler(union control *ctrl, void *dlg,
48 void *data, int event)
51 Conf *conf = (Conf *)data;
54 * For a standard checkbox, the context parameter gives the
55 * primary key (CONF_foo), optionally ORed with CHECKBOX_INVERT.
57 key = ctrl->checkbox.context.i;
58 if (key & CHECKBOX_INVERT) {
59 key &= ~CHECKBOX_INVERT;
65 * C lacks a logical XOR, so the following code uses the idiom
66 * (!a ^ !b) to obtain the logical XOR of a and b. (That is, 1
67 * iff exactly one of a and b is nonzero, otherwise 0.)
70 if (event == EVENT_REFRESH) {
71 int val = conf_get_int(conf, key);
72 dlg_checkbox_set(ctrl, dlg, (!val ^ !invert));
73 } else if (event == EVENT_VALCHANGE) {
74 conf_set_int(conf, key, !dlg_checkbox_get(ctrl,dlg) ^ !invert);
78 void conf_editbox_handler(union control *ctrl, void *dlg,
79 void *data, int event)
82 * The standard edit-box handler expects the main `context'
83 * field to contain the primary key. The secondary `context2'
84 * field indicates the type of this field:
86 * - if context2 > 0, the field is a string.
87 * - if context2 == -1, the field is an int and the edit box
89 * - if context2 < -1, the field is an int and the edit box is
90 * _floating_, and (-context2) gives the scale. (E.g. if
91 * context2 == -1000, then typing 1.2 into the box will set
94 int key = ctrl->editbox.context.i;
95 int length = ctrl->editbox.context2.i;
96 Conf *conf = (Conf *)data;
99 if (event == EVENT_REFRESH) {
100 char *field = conf_get_str(conf, key);
101 dlg_editbox_set(ctrl, dlg, field);
102 } else if (event == EVENT_VALCHANGE) {
103 char *field = dlg_editbox_get(ctrl, dlg);
104 conf_set_str(conf, key, field);
107 } else if (length < 0) {
108 if (event == EVENT_REFRESH) {
110 int value = conf_get_int(conf, key);
112 sprintf(str, "%d", value);
114 sprintf(str, "%g", (double)value / (double)(-length));
115 dlg_editbox_set(ctrl, dlg, str);
116 } else if (event == EVENT_VALCHANGE) {
117 char *str = dlg_editbox_get(ctrl, dlg);
119 conf_set_int(conf, key, atoi(str));
121 conf_set_int(conf, key, (int)((-length) * atof(str)));
127 void conf_filesel_handler(union control *ctrl, void *dlg,
128 void *data, int event)
130 int key = ctrl->fileselect.context.i;
131 Conf *conf = (Conf *)data;
133 if (event == EVENT_REFRESH) {
134 dlg_filesel_set(ctrl, dlg, conf_get_filename(conf, key));
135 } else if (event == EVENT_VALCHANGE) {
136 Filename *filename = dlg_filesel_get(ctrl, dlg);
137 conf_set_filename(conf, key, filename);
138 filename_free(filename);
142 void conf_fontsel_handler(union control *ctrl, void *dlg,
143 void *data, int event)
145 int key = ctrl->fontselect.context.i;
146 Conf *conf = (Conf *)data;
148 if (event == EVENT_REFRESH) {
149 dlg_fontsel_set(ctrl, dlg, conf_get_fontspec(conf, key));
150 } else if (event == EVENT_VALCHANGE) {
151 FontSpec *fontspec = dlg_fontsel_get(ctrl, dlg);
152 conf_set_fontspec(conf, key, fontspec);
153 fontspec_free(fontspec);
157 static void config_host_handler(union control *ctrl, void *dlg,
158 void *data, int event)
160 Conf *conf = (Conf *)data;
163 * This function works just like the standard edit box handler,
164 * only it has to choose the control's label and text from two
165 * different places depending on the protocol.
167 if (event == EVENT_REFRESH) {
168 if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL) {
170 * This label text is carefully chosen to contain an n,
171 * since that's the shortcut for the host name control.
173 dlg_label_change(ctrl, dlg, "Serial line");
174 dlg_editbox_set(ctrl, dlg, conf_get_str(conf, CONF_serline));
176 dlg_label_change(ctrl, dlg, HOST_BOX_TITLE);
177 dlg_editbox_set(ctrl, dlg, conf_get_str(conf, CONF_host));
179 } else if (event == EVENT_VALCHANGE) {
180 char *s = dlg_editbox_get(ctrl, dlg);
181 if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL)
182 conf_set_str(conf, CONF_serline, s);
184 conf_set_str(conf, CONF_host, s);
189 static void config_port_handler(union control *ctrl, void *dlg,
190 void *data, int event)
192 Conf *conf = (Conf *)data;
196 * This function works similarly to the standard edit box handler,
197 * only it has to choose the control's label and text from two
198 * different places depending on the protocol.
200 if (event == EVENT_REFRESH) {
201 if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL) {
203 * This label text is carefully chosen to contain a p,
204 * since that's the shortcut for the port control.
206 dlg_label_change(ctrl, dlg, "Speed");
207 sprintf(buf, "%d", conf_get_int(conf, CONF_serspeed));
209 dlg_label_change(ctrl, dlg, PORT_BOX_TITLE);
210 if (conf_get_int(conf, CONF_port) != 0)
211 sprintf(buf, "%d", conf_get_int(conf, CONF_port));
213 /* Display an (invalid) port of 0 as blank */
216 dlg_editbox_set(ctrl, dlg, buf);
217 } else if (event == EVENT_VALCHANGE) {
218 char *s = dlg_editbox_get(ctrl, dlg);
222 if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL)
223 conf_set_int(conf, CONF_serspeed, i);
225 conf_set_int(conf, CONF_port, i);
230 union control *host, *port;
234 * We export this function so that platform-specific config
235 * routines can use it to conveniently identify the protocol radio
236 * buttons in order to add to them.
238 void config_protocolbuttons_handler(union control *ctrl, void *dlg,
239 void *data, int event)
242 Conf *conf = (Conf *)data;
243 struct hostport *hp = (struct hostport *)ctrl->radio.context.p;
246 * This function works just like the standard radio-button
247 * handler, except that it also has to change the setting of
248 * the port box, and refresh both host and port boxes when. We
249 * expect the context parameter to point at a hostport
250 * structure giving the `union control's for both.
252 if (event == EVENT_REFRESH) {
253 int protocol = conf_get_int(conf, CONF_protocol);
254 for (button = 0; button < ctrl->radio.nbuttons; button++)
255 if (protocol == ctrl->radio.buttondata[button].i)
257 /* We expected that `break' to happen, in all circumstances. */
258 assert(button < ctrl->radio.nbuttons);
259 dlg_radiobutton_set(ctrl, dlg, button);
260 } else if (event == EVENT_VALCHANGE) {
261 int oldproto = conf_get_int(conf, CONF_protocol);
264 button = dlg_radiobutton_get(ctrl, dlg);
265 assert(button >= 0 && button < ctrl->radio.nbuttons);
266 newproto = ctrl->radio.buttondata[button].i;
267 conf_set_int(conf, CONF_protocol, newproto);
269 if (oldproto != newproto) {
270 Backend *ob = backend_from_proto(oldproto);
271 Backend *nb = backend_from_proto(newproto);
274 /* Iff the user hasn't changed the port from the old protocol's
275 * default, update it with the new protocol's default.
276 * (This includes a "default" of 0, implying that there is no
277 * sensible default for that protocol; in this case it's
278 * displayed as a blank.)
279 * This helps with the common case of tabbing through the
280 * controls in order and setting a non-default port before
281 * getting to the protocol; we want that non-default port
282 * to be preserved. */
283 port = conf_get_int(conf, CONF_port);
284 if (port == ob->default_port)
285 conf_set_int(conf, CONF_port, nb->default_port);
287 dlg_refresh(hp->host, dlg);
288 dlg_refresh(hp->port, dlg);
292 static void loggingbuttons_handler(union control *ctrl, void *dlg,
293 void *data, int event)
296 Conf *conf = (Conf *)data;
297 /* This function works just like the standard radio-button handler,
298 * but it has to fall back to "no logging" in situations where the
299 * configured logging type isn't applicable.
301 if (event == EVENT_REFRESH) {
302 int logtype = conf_get_int(conf, CONF_logtype);
304 for (button = 0; button < ctrl->radio.nbuttons; button++)
305 if (logtype == ctrl->radio.buttondata[button].i)
308 /* We fell off the end, so we lack the configured logging type */
309 if (button == ctrl->radio.nbuttons) {
311 conf_set_int(conf, CONF_logtype, LGTYP_NONE);
313 dlg_radiobutton_set(ctrl, dlg, button);
314 } else if (event == EVENT_VALCHANGE) {
315 button = dlg_radiobutton_get(ctrl, dlg);
316 assert(button >= 0 && button < ctrl->radio.nbuttons);
317 conf_set_int(conf, CONF_logtype, ctrl->radio.buttondata[button].i);
321 static void numeric_keypad_handler(union control *ctrl, void *dlg,
322 void *data, int event)
325 Conf *conf = (Conf *)data;
327 * This function works much like the standard radio button
328 * handler, but it has to handle two fields in Conf.
330 if (event == EVENT_REFRESH) {
331 if (conf_get_int(conf, CONF_nethack_keypad))
333 else if (conf_get_int(conf, CONF_app_keypad))
337 assert(button < ctrl->radio.nbuttons);
338 dlg_radiobutton_set(ctrl, dlg, button);
339 } else if (event == EVENT_VALCHANGE) {
340 button = dlg_radiobutton_get(ctrl, dlg);
341 assert(button >= 0 && button < ctrl->radio.nbuttons);
343 conf_set_int(conf, CONF_app_keypad, FALSE);
344 conf_set_int(conf, CONF_nethack_keypad, TRUE);
346 conf_set_int(conf, CONF_app_keypad, (button != 0));
347 conf_set_int(conf, CONF_nethack_keypad, FALSE);
352 static void cipherlist_handler(union control *ctrl, void *dlg,
353 void *data, int event)
355 Conf *conf = (Conf *)data;
356 if (event == EVENT_REFRESH) {
359 static const struct { const char *s; int c; } ciphers[] = {
360 { "3DES", CIPHER_3DES },
361 { "Blowfish", CIPHER_BLOWFISH },
362 { "DES", CIPHER_DES },
363 { "AES (SSH-2 only)", CIPHER_AES },
364 { "Arcfour (SSH-2 only)", CIPHER_ARCFOUR },
365 { "-- warn below here --", CIPHER_WARN }
368 /* Set up the "selected ciphers" box. */
369 /* (cipherlist assumed to contain all ciphers) */
370 dlg_update_start(ctrl, dlg);
371 dlg_listbox_clear(ctrl, dlg);
372 for (i = 0; i < CIPHER_MAX; i++) {
373 int c = conf_get_int_int(conf, CONF_ssh_cipherlist, i);
375 const char *cstr = NULL;
376 for (j = 0; j < (sizeof ciphers) / (sizeof ciphers[0]); j++) {
377 if (ciphers[j].c == c) {
382 dlg_listbox_addwithid(ctrl, dlg, cstr, c);
384 dlg_update_done(ctrl, dlg);
386 } else if (event == EVENT_VALCHANGE) {
389 /* Update array to match the list box. */
390 for (i=0; i < CIPHER_MAX; i++)
391 conf_set_int_int(conf, CONF_ssh_cipherlist, i,
392 dlg_listbox_getid(ctrl, dlg, i));
397 static void gsslist_handler(union control *ctrl, void *dlg,
398 void *data, int event)
400 Conf *conf = (Conf *)data;
401 if (event == EVENT_REFRESH) {
404 dlg_update_start(ctrl, dlg);
405 dlg_listbox_clear(ctrl, dlg);
406 for (i = 0; i < ngsslibs; i++) {
407 int id = conf_get_int_int(conf, CONF_ssh_gsslist, i);
408 assert(id >= 0 && id < ngsslibs);
409 dlg_listbox_addwithid(ctrl, dlg, gsslibnames[id], id);
411 dlg_update_done(ctrl, dlg);
413 } else if (event == EVENT_VALCHANGE) {
416 /* Update array to match the list box. */
417 for (i=0; i < ngsslibs; i++)
418 conf_set_int_int(conf, CONF_ssh_gsslist, i,
419 dlg_listbox_getid(ctrl, dlg, i));
424 static void kexlist_handler(union control *ctrl, void *dlg,
425 void *data, int event)
427 Conf *conf = (Conf *)data;
428 if (event == EVENT_REFRESH) {
431 static const struct { const char *s; int k; } kexes[] = {
432 { "Diffie-Hellman group 1", KEX_DHGROUP1 },
433 { "Diffie-Hellman group 14", KEX_DHGROUP14 },
434 { "Diffie-Hellman group exchange", KEX_DHGEX },
435 { "RSA-based key exchange", KEX_RSA },
436 { "ECDH key exchange", KEX_ECDH },
437 { "-- warn below here --", KEX_WARN }
440 /* Set up the "kex preference" box. */
441 /* (kexlist assumed to contain all algorithms) */
442 dlg_update_start(ctrl, dlg);
443 dlg_listbox_clear(ctrl, dlg);
444 for (i = 0; i < KEX_MAX; i++) {
445 int k = conf_get_int_int(conf, CONF_ssh_kexlist, i);
447 const char *kstr = NULL;
448 for (j = 0; j < (sizeof kexes) / (sizeof kexes[0]); j++) {
449 if (kexes[j].k == k) {
454 dlg_listbox_addwithid(ctrl, dlg, kstr, k);
456 dlg_update_done(ctrl, dlg);
458 } else if (event == EVENT_VALCHANGE) {
461 /* Update array to match the list box. */
462 for (i=0; i < KEX_MAX; i++)
463 conf_set_int_int(conf, CONF_ssh_kexlist, i,
464 dlg_listbox_getid(ctrl, dlg, i));
468 static void printerbox_handler(union control *ctrl, void *dlg,
469 void *data, int event)
471 Conf *conf = (Conf *)data;
472 if (event == EVENT_REFRESH) {
477 dlg_update_start(ctrl, dlg);
479 * Some backends may wish to disable the drop-down list on
480 * this edit box. Be prepared for this.
482 if (ctrl->editbox.has_list) {
483 dlg_listbox_clear(ctrl, dlg);
484 dlg_listbox_add(ctrl, dlg, PRINTER_DISABLED_STRING);
485 pe = printer_start_enum(&nprinters);
486 for (i = 0; i < nprinters; i++)
487 dlg_listbox_add(ctrl, dlg, printer_get_name(pe, i));
488 printer_finish_enum(pe);
490 printer = conf_get_str(conf, CONF_printer);
492 printer = PRINTER_DISABLED_STRING;
493 dlg_editbox_set(ctrl, dlg, printer);
494 dlg_update_done(ctrl, dlg);
495 } else if (event == EVENT_VALCHANGE) {
496 char *printer = dlg_editbox_get(ctrl, dlg);
497 if (!strcmp(printer, PRINTER_DISABLED_STRING))
499 conf_set_str(conf, CONF_printer, printer);
504 static void codepage_handler(union control *ctrl, void *dlg,
505 void *data, int event)
507 Conf *conf = (Conf *)data;
508 if (event == EVENT_REFRESH) {
510 const char *cp, *thiscp;
511 dlg_update_start(ctrl, dlg);
512 thiscp = cp_name(decode_codepage(conf_get_str(conf,
513 CONF_line_codepage)));
514 dlg_listbox_clear(ctrl, dlg);
515 for (i = 0; (cp = cp_enumerate(i)) != NULL; i++)
516 dlg_listbox_add(ctrl, dlg, cp);
517 dlg_editbox_set(ctrl, dlg, thiscp);
518 conf_set_str(conf, CONF_line_codepage, thiscp);
519 dlg_update_done(ctrl, dlg);
520 } else if (event == EVENT_VALCHANGE) {
521 char *codepage = dlg_editbox_get(ctrl, dlg);
522 conf_set_str(conf, CONF_line_codepage,
523 cp_name(decode_codepage(codepage)));
528 static void sshbug_handler(union control *ctrl, void *dlg,
529 void *data, int event)
531 Conf *conf = (Conf *)data;
532 if (event == EVENT_REFRESH) {
534 * We must fetch the previously configured value from the Conf
535 * before we start modifying the drop-down list, otherwise the
536 * spurious SELCHANGE we trigger in the process will overwrite
537 * the value we wanted to keep.
539 int oldconf = conf_get_int(conf, ctrl->listbox.context.i);
540 dlg_update_start(ctrl, dlg);
541 dlg_listbox_clear(ctrl, dlg);
542 dlg_listbox_addwithid(ctrl, dlg, "Auto", AUTO);
543 dlg_listbox_addwithid(ctrl, dlg, "Off", FORCE_OFF);
544 dlg_listbox_addwithid(ctrl, dlg, "On", FORCE_ON);
546 case AUTO: dlg_listbox_select(ctrl, dlg, 0); break;
547 case FORCE_OFF: dlg_listbox_select(ctrl, dlg, 1); break;
548 case FORCE_ON: dlg_listbox_select(ctrl, dlg, 2); break;
550 dlg_update_done(ctrl, dlg);
551 } else if (event == EVENT_SELCHANGE) {
552 int i = dlg_listbox_index(ctrl, dlg);
556 i = dlg_listbox_getid(ctrl, dlg, i);
557 conf_set_int(conf, ctrl->listbox.context.i, i);
561 struct sessionsaver_data {
562 union control *editbox, *listbox, *loadbutton, *savebutton, *delbutton;
563 union control *okbutton, *cancelbutton;
564 struct sesslist sesslist;
566 char *savedsession; /* the current contents of ssd->editbox */
569 static void sessionsaver_data_free(void *ssdv)
571 struct sessionsaver_data *ssd = (struct sessionsaver_data *)ssdv;
572 get_sesslist(&ssd->sesslist, FALSE);
573 sfree(ssd->savedsession);
578 * Helper function to load the session selected in the list box, if
579 * any, as this is done in more than one place below. Returns 0 for
582 static int load_selected_session(struct sessionsaver_data *ssd,
583 void *dlg, Conf *conf, int *maybe_launch)
585 int i = dlg_listbox_index(ssd->listbox, dlg);
591 isdef = !strcmp(ssd->sesslist.sessions[i], "Default Settings");
592 load_settings(ssd->sesslist.sessions[i], conf);
593 sfree(ssd->savedsession);
594 ssd->savedsession = dupstr(isdef ? "" : ssd->sesslist.sessions[i]);
596 *maybe_launch = !isdef;
597 dlg_refresh(NULL, dlg);
598 /* Restore the selection, which might have been clobbered by
599 * changing the value of the edit box. */
600 dlg_listbox_select(ssd->listbox, dlg, i);
604 static void sessionsaver_handler(union control *ctrl, void *dlg,
605 void *data, int event)
607 Conf *conf = (Conf *)data;
608 struct sessionsaver_data *ssd =
609 (struct sessionsaver_data *)ctrl->generic.context.p;
611 if (event == EVENT_REFRESH) {
612 if (ctrl == ssd->editbox) {
613 dlg_editbox_set(ctrl, dlg, ssd->savedsession);
614 } else if (ctrl == ssd->listbox) {
616 dlg_update_start(ctrl, dlg);
617 dlg_listbox_clear(ctrl, dlg);
618 for (i = 0; i < ssd->sesslist.nsessions; i++)
619 dlg_listbox_add(ctrl, dlg, ssd->sesslist.sessions[i]);
620 dlg_update_done(ctrl, dlg);
622 } else if (event == EVENT_VALCHANGE) {
623 int top, bottom, halfway, i;
624 if (ctrl == ssd->editbox) {
625 sfree(ssd->savedsession);
626 ssd->savedsession = dlg_editbox_get(ctrl, dlg);
627 top = ssd->sesslist.nsessions;
629 while (top-bottom > 1) {
630 halfway = (top+bottom)/2;
631 i = strcmp(ssd->savedsession, ssd->sesslist.sessions[halfway]);
638 if (top == ssd->sesslist.nsessions) {
641 dlg_listbox_select(ssd->listbox, dlg, top);
643 } else if (event == EVENT_ACTION) {
645 if (!ssd->midsession &&
646 (ctrl == ssd->listbox ||
647 (ssd->loadbutton && ctrl == ssd->loadbutton))) {
649 * The user has double-clicked a session, or hit Load.
650 * We must load the selected session, and then
651 * terminate the configuration dialog _if_ there was a
652 * double-click on the list box _and_ that session
653 * contains a hostname.
655 if (load_selected_session(ssd, dlg, conf, &mbl) &&
656 (mbl && ctrl == ssd->listbox && conf_launchable(conf))) {
657 dlg_end(dlg, 1); /* it's all over, and succeeded */
659 } else if (ctrl == ssd->savebutton) {
660 int isdef = !strcmp(ssd->savedsession, "Default Settings");
661 if (!ssd->savedsession[0]) {
662 int i = dlg_listbox_index(ssd->listbox, dlg);
667 isdef = !strcmp(ssd->sesslist.sessions[i], "Default Settings");
668 sfree(ssd->savedsession);
669 ssd->savedsession = dupstr(isdef ? "" :
670 ssd->sesslist.sessions[i]);
673 char *errmsg = save_settings(ssd->savedsession, conf);
675 dlg_error_msg(dlg, errmsg);
679 get_sesslist(&ssd->sesslist, FALSE);
680 get_sesslist(&ssd->sesslist, TRUE);
681 dlg_refresh(ssd->editbox, dlg);
682 dlg_refresh(ssd->listbox, dlg);
683 } else if (!ssd->midsession &&
684 ssd->delbutton && ctrl == ssd->delbutton) {
685 int i = dlg_listbox_index(ssd->listbox, dlg);
689 del_settings(ssd->sesslist.sessions[i]);
690 get_sesslist(&ssd->sesslist, FALSE);
691 get_sesslist(&ssd->sesslist, TRUE);
692 dlg_refresh(ssd->listbox, dlg);
694 } else if (ctrl == ssd->okbutton) {
695 if (ssd->midsession) {
696 /* In a mid-session Change Settings, Apply is always OK. */
701 * Annoying special case. If the `Open' button is
702 * pressed while no host name is currently set, _and_
703 * the session list previously had the focus, _and_
704 * there was a session selected in that which had a
705 * valid host name in it, then load it and go.
707 if (dlg_last_focused(ctrl, dlg) == ssd->listbox &&
708 !conf_launchable(conf)) {
709 Conf *conf2 = conf_new();
711 if (!load_selected_session(ssd, dlg, conf2, &mbl)) {
716 /* If at this point we have a valid session, go! */
717 if (mbl && conf_launchable(conf2)) {
718 conf_copy_into(conf, conf2);
728 * Otherwise, do the normal thing: if we have a valid
729 * session, get going.
731 if (conf_launchable(conf)) {
735 } else if (ctrl == ssd->cancelbutton) {
741 struct charclass_data {
742 union control *listbox, *editbox, *button;
745 static void charclass_handler(union control *ctrl, void *dlg,
746 void *data, int event)
748 Conf *conf = (Conf *)data;
749 struct charclass_data *ccd =
750 (struct charclass_data *)ctrl->generic.context.p;
752 if (event == EVENT_REFRESH) {
753 if (ctrl == ccd->listbox) {
755 dlg_update_start(ctrl, dlg);
756 dlg_listbox_clear(ctrl, dlg);
757 for (i = 0; i < 128; i++) {
759 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
760 (i >= 0x21 && i != 0x7F) ? i : ' ',
761 conf_get_int_int(conf, CONF_wordness, i));
762 dlg_listbox_add(ctrl, dlg, str);
764 dlg_update_done(ctrl, dlg);
766 } else if (event == EVENT_ACTION) {
767 if (ctrl == ccd->button) {
770 str = dlg_editbox_get(ccd->editbox, dlg);
773 for (i = 0; i < 128; i++) {
774 if (dlg_listbox_issel(ccd->listbox, dlg, i))
775 conf_set_int_int(conf, CONF_wordness, i, n);
777 dlg_refresh(ccd->listbox, dlg);
783 union control *listbox, *redit, *gedit, *bedit, *button;
786 static const char *const colours[] = {
787 "Default Foreground", "Default Bold Foreground",
788 "Default Background", "Default Bold Background",
789 "Cursor Text", "Cursor Colour",
790 "ANSI Black", "ANSI Black Bold",
791 "ANSI Red", "ANSI Red Bold",
792 "ANSI Green", "ANSI Green Bold",
793 "ANSI Yellow", "ANSI Yellow Bold",
794 "ANSI Blue", "ANSI Blue Bold",
795 "ANSI Magenta", "ANSI Magenta Bold",
796 "ANSI Cyan", "ANSI Cyan Bold",
797 "ANSI White", "ANSI White Bold"
800 static void colour_handler(union control *ctrl, void *dlg,
801 void *data, int event)
803 Conf *conf = (Conf *)data;
804 struct colour_data *cd =
805 (struct colour_data *)ctrl->generic.context.p;
806 int update = FALSE, clear = FALSE, r, g, b;
808 if (event == EVENT_REFRESH) {
809 if (ctrl == cd->listbox) {
811 dlg_update_start(ctrl, dlg);
812 dlg_listbox_clear(ctrl, dlg);
813 for (i = 0; i < lenof(colours); i++)
814 dlg_listbox_add(ctrl, dlg, colours[i]);
815 dlg_update_done(ctrl, dlg);
819 } else if (event == EVENT_SELCHANGE) {
820 if (ctrl == cd->listbox) {
821 /* The user has selected a colour. Update the RGB text. */
822 int i = dlg_listbox_index(ctrl, dlg);
827 r = conf_get_int_int(conf, CONF_colours, i*3+0);
828 g = conf_get_int_int(conf, CONF_colours, i*3+1);
829 b = conf_get_int_int(conf, CONF_colours, i*3+2);
833 } else if (event == EVENT_VALCHANGE) {
834 if (ctrl == cd->redit || ctrl == cd->gedit || ctrl == cd->bedit) {
835 /* The user has changed the colour using the edit boxes. */
839 str = dlg_editbox_get(ctrl, dlg);
842 if (cval > 255) cval = 255;
843 if (cval < 0) cval = 0;
845 i = dlg_listbox_index(cd->listbox, dlg);
847 if (ctrl == cd->redit)
848 conf_set_int_int(conf, CONF_colours, i*3+0, cval);
849 else if (ctrl == cd->gedit)
850 conf_set_int_int(conf, CONF_colours, i*3+1, cval);
851 else if (ctrl == cd->bedit)
852 conf_set_int_int(conf, CONF_colours, i*3+2, cval);
855 } else if (event == EVENT_ACTION) {
856 if (ctrl == cd->button) {
857 int i = dlg_listbox_index(cd->listbox, dlg);
863 * Start a colour selector, which will send us an
864 * EVENT_CALLBACK when it's finished and allow us to
865 * pick up the results.
867 dlg_coloursel_start(ctrl, dlg,
868 conf_get_int_int(conf, CONF_colours, i*3+0),
869 conf_get_int_int(conf, CONF_colours, i*3+1),
870 conf_get_int_int(conf, CONF_colours, i*3+2));
872 } else if (event == EVENT_CALLBACK) {
873 if (ctrl == cd->button) {
874 int i = dlg_listbox_index(cd->listbox, dlg);
876 * Collect the results of the colour selector. Will
877 * return nonzero on success, or zero if the colour
878 * selector did nothing (user hit Cancel, for example).
880 if (dlg_coloursel_results(ctrl, dlg, &r, &g, &b)) {
881 conf_set_int_int(conf, CONF_colours, i*3+0, r);
882 conf_set_int_int(conf, CONF_colours, i*3+1, g);
883 conf_set_int_int(conf, CONF_colours, i*3+2, b);
892 dlg_editbox_set(cd->redit, dlg, "");
893 dlg_editbox_set(cd->gedit, dlg, "");
894 dlg_editbox_set(cd->bedit, dlg, "");
897 sprintf(buf, "%d", r); dlg_editbox_set(cd->redit, dlg, buf);
898 sprintf(buf, "%d", g); dlg_editbox_set(cd->gedit, dlg, buf);
899 sprintf(buf, "%d", b); dlg_editbox_set(cd->bedit, dlg, buf);
904 struct ttymodes_data {
905 union control *modelist, *valradio, *valbox;
906 union control *addbutton, *rembutton, *listbox;
909 static void ttymodes_handler(union control *ctrl, void *dlg,
910 void *data, int event)
912 Conf *conf = (Conf *)data;
913 struct ttymodes_data *td =
914 (struct ttymodes_data *)ctrl->generic.context.p;
916 if (event == EVENT_REFRESH) {
917 if (ctrl == td->listbox) {
919 dlg_update_start(ctrl, dlg);
920 dlg_listbox_clear(ctrl, dlg);
921 for (val = conf_get_str_strs(conf, CONF_ttymodes, NULL, &key);
923 val = conf_get_str_strs(conf, CONF_ttymodes, key, &key)) {
924 char *disp = dupprintf("%s\t%s", key,
925 (val[0] == 'A') ? "(auto)" : val+1);
926 dlg_listbox_add(ctrl, dlg, disp);
929 dlg_update_done(ctrl, dlg);
930 } else if (ctrl == td->modelist) {
932 dlg_update_start(ctrl, dlg);
933 dlg_listbox_clear(ctrl, dlg);
934 for (i = 0; ttymodes[i]; i++)
935 dlg_listbox_add(ctrl, dlg, ttymodes[i]);
936 dlg_listbox_select(ctrl, dlg, 0); /* *shrug* */
937 dlg_update_done(ctrl, dlg);
938 } else if (ctrl == td->valradio) {
939 dlg_radiobutton_set(ctrl, dlg, 0);
941 } else if (event == EVENT_ACTION) {
942 if (ctrl == td->addbutton) {
943 int ind = dlg_listbox_index(td->modelist, dlg);
945 char type = dlg_radiobutton_get(td->valradio, dlg) ? 'V' : 'A';
948 /* Construct new entry */
950 str = dlg_editbox_get(td->valbox, dlg);
951 val = dupprintf("%c%s", type, str);
953 conf_set_str_str(conf, CONF_ttymodes, key, val);
955 dlg_refresh(td->listbox, dlg);
958 } else if (ctrl == td->rembutton) {
961 int multisel = dlg_listbox_index(td->listbox, dlg) < 0;
962 for (val = conf_get_str_strs(conf, CONF_ttymodes, NULL, &key);
964 val = conf_get_str_strs(conf, CONF_ttymodes, key, &key)) {
965 if (dlg_listbox_issel(td->listbox, dlg, i)) {
967 /* Populate controls with entry we're about to
968 * delete, for ease of editing.
969 * (If multiple entries were selected, don't
970 * touch the controls.) */
973 while (ttymodes[ind]) {
974 if (!strcmp(ttymodes[ind], key))
978 dlg_listbox_select(td->modelist, dlg, ind);
979 dlg_radiobutton_set(td->valradio, dlg,
981 dlg_editbox_set(td->valbox, dlg, val+1);
983 conf_del_str_str(conf, CONF_ttymodes, key);
987 dlg_refresh(td->listbox, dlg);
992 struct environ_data {
993 union control *varbox, *valbox, *addbutton, *rembutton, *listbox;
996 static void environ_handler(union control *ctrl, void *dlg,
997 void *data, int event)
999 Conf *conf = (Conf *)data;
1000 struct environ_data *ed =
1001 (struct environ_data *)ctrl->generic.context.p;
1003 if (event == EVENT_REFRESH) {
1004 if (ctrl == ed->listbox) {
1006 dlg_update_start(ctrl, dlg);
1007 dlg_listbox_clear(ctrl, dlg);
1008 for (val = conf_get_str_strs(conf, CONF_environmt, NULL, &key);
1010 val = conf_get_str_strs(conf, CONF_environmt, key, &key)) {
1011 char *p = dupprintf("%s\t%s", key, val);
1012 dlg_listbox_add(ctrl, dlg, p);
1015 dlg_update_done(ctrl, dlg);
1017 } else if (event == EVENT_ACTION) {
1018 if (ctrl == ed->addbutton) {
1019 char *key, *val, *str;
1020 key = dlg_editbox_get(ed->varbox, dlg);
1026 val = dlg_editbox_get(ed->valbox, dlg);
1033 conf_set_str_str(conf, CONF_environmt, key, val);
1034 str = dupcat(key, "\t", val, NULL);
1035 dlg_editbox_set(ed->varbox, dlg, "");
1036 dlg_editbox_set(ed->valbox, dlg, "");
1040 dlg_refresh(ed->listbox, dlg);
1041 } else if (ctrl == ed->rembutton) {
1042 int i = dlg_listbox_index(ed->listbox, dlg);
1048 key = conf_get_str_nthstrkey(conf, CONF_environmt, i);
1050 /* Populate controls with the entry we're about to delete
1051 * for ease of editing */
1052 val = conf_get_str_str(conf, CONF_environmt, key);
1053 dlg_editbox_set(ed->varbox, dlg, key);
1054 dlg_editbox_set(ed->valbox, dlg, val);
1056 conf_del_str_str(conf, CONF_environmt, key);
1059 dlg_refresh(ed->listbox, dlg);
1064 struct portfwd_data {
1065 union control *addbutton, *rembutton, *listbox;
1066 union control *sourcebox, *destbox, *direction;
1068 union control *addressfamily;
1072 static void portfwd_handler(union control *ctrl, void *dlg,
1073 void *data, int event)
1075 Conf *conf = (Conf *)data;
1076 struct portfwd_data *pfd =
1077 (struct portfwd_data *)ctrl->generic.context.p;
1079 if (event == EVENT_REFRESH) {
1080 if (ctrl == pfd->listbox) {
1082 dlg_update_start(ctrl, dlg);
1083 dlg_listbox_clear(ctrl, dlg);
1084 for (val = conf_get_str_strs(conf, CONF_portfwd, NULL, &key);
1086 val = conf_get_str_strs(conf, CONF_portfwd, key, &key)) {
1088 if (!strcmp(val, "D")) {
1091 * A dynamic forwarding is stored as L12345=D or
1092 * 6L12345=D (since it's mutually exclusive with
1093 * L12345=anything else), but displayed as D12345
1094 * to match the fiction that 'Local', 'Remote' and
1095 * 'Dynamic' are three distinct modes and also to
1096 * align with OpenSSH's command line option syntax
1097 * that people will already be used to. So, for
1098 * display purposes, find the L in the key string
1099 * and turn it into a D.
1101 p = dupprintf("%s\t", key);
1105 p = dupprintf("%s\t%s", key, val);
1106 dlg_listbox_add(ctrl, dlg, p);
1109 dlg_update_done(ctrl, dlg);
1110 } else if (ctrl == pfd->direction) {
1114 dlg_radiobutton_set(ctrl, dlg, 0);
1116 } else if (ctrl == pfd->addressfamily) {
1117 dlg_radiobutton_set(ctrl, dlg, 0);
1120 } else if (event == EVENT_ACTION) {
1121 if (ctrl == pfd->addbutton) {
1122 const char *family, *type;
1123 char *src, *key, *val;
1127 whichbutton = dlg_radiobutton_get(pfd->addressfamily, dlg);
1128 if (whichbutton == 1)
1130 else if (whichbutton == 2)
1136 whichbutton = dlg_radiobutton_get(pfd->direction, dlg);
1137 if (whichbutton == 0)
1139 else if (whichbutton == 1)
1144 src = dlg_editbox_get(pfd->sourcebox, dlg);
1146 dlg_error_msg(dlg, "You need to specify a source port number");
1151 val = dlg_editbox_get(pfd->destbox, dlg);
1152 if (!*val || !host_strchr(val, ':')) {
1154 "You need to specify a destination address\n"
1155 "in the form \"host.name:port\"");
1162 val = dupstr("D"); /* special case */
1165 key = dupcat(family, type, src, NULL);
1168 if (conf_get_str_str_opt(conf, CONF_portfwd, key)) {
1169 dlg_error_msg(dlg, "Specified forwarding already exists");
1171 conf_set_str_str(conf, CONF_portfwd, key, val);
1176 dlg_refresh(pfd->listbox, dlg);
1177 } else if (ctrl == pfd->rembutton) {
1178 int i = dlg_listbox_index(pfd->listbox, dlg);
1185 key = conf_get_str_nthstrkey(conf, CONF_portfwd, i);
1187 static const char *const afs = "A46";
1188 static const char *const dirs = "LRD";
1195 /* Populate controls with the entry we're about to delete
1196 * for ease of editing */
1199 afp = strchr(afs, *p);
1201 idx = afp ? afp-afs : 0;
1206 dlg_radiobutton_set(pfd->addressfamily, dlg, idx);
1211 val = conf_get_str_str(conf, CONF_portfwd, key);
1212 if (!strcmp(val, "D")) {
1217 dlg_radiobutton_set(pfd->direction, dlg,
1218 strchr(dirs, dir) - dirs);
1221 dlg_editbox_set(pfd->sourcebox, dlg, p);
1222 dlg_editbox_set(pfd->destbox, dlg, val);
1224 conf_del_str_str(conf, CONF_portfwd, key);
1227 dlg_refresh(pfd->listbox, dlg);
1232 struct manual_hostkey_data {
1233 union control *addbutton, *rembutton, *listbox, *keybox;
1236 static void manual_hostkey_handler(union control *ctrl, void *dlg,
1237 void *data, int event)
1239 Conf *conf = (Conf *)data;
1240 struct manual_hostkey_data *mh =
1241 (struct manual_hostkey_data *)ctrl->generic.context.p;
1243 if (event == EVENT_REFRESH) {
1244 if (ctrl == mh->listbox) {
1246 dlg_update_start(ctrl, dlg);
1247 dlg_listbox_clear(ctrl, dlg);
1248 for (val = conf_get_str_strs(conf, CONF_ssh_manual_hostkeys,
1251 val = conf_get_str_strs(conf, CONF_ssh_manual_hostkeys,
1253 dlg_listbox_add(ctrl, dlg, key);
1255 dlg_update_done(ctrl, dlg);
1257 } else if (event == EVENT_ACTION) {
1258 if (ctrl == mh->addbutton) {
1261 key = dlg_editbox_get(mh->keybox, dlg);
1263 dlg_error_msg(dlg, "You need to specify a host key or "
1269 if (!validate_manual_hostkey(key)) {
1270 dlg_error_msg(dlg, "Host key is not in a valid format");
1271 } else if (conf_get_str_str_opt(conf, CONF_ssh_manual_hostkeys,
1273 dlg_error_msg(dlg, "Specified host key is already listed");
1275 conf_set_str_str(conf, CONF_ssh_manual_hostkeys, key, "");
1279 dlg_refresh(mh->listbox, dlg);
1280 } else if (ctrl == mh->rembutton) {
1281 int i = dlg_listbox_index(mh->listbox, dlg);
1287 key = conf_get_str_nthstrkey(conf, CONF_ssh_manual_hostkeys, i);
1289 dlg_editbox_set(mh->keybox, dlg, key);
1291 conf_del_str_str(conf, CONF_ssh_manual_hostkeys, key);
1294 dlg_refresh(mh->listbox, dlg);
1299 void setup_config_box(struct controlbox *b, int midsession,
1300 int protocol, int protcfginfo)
1302 struct controlset *s;
1303 struct sessionsaver_data *ssd;
1304 struct charclass_data *ccd;
1305 struct colour_data *cd;
1306 struct ttymodes_data *td;
1307 struct environ_data *ed;
1308 struct portfwd_data *pfd;
1309 struct manual_hostkey_data *mh;
1313 ssd = (struct sessionsaver_data *)
1314 ctrl_alloc_with_free(b, sizeof(struct sessionsaver_data),
1315 sessionsaver_data_free);
1316 memset(ssd, 0, sizeof(*ssd));
1317 ssd->savedsession = dupstr("");
1318 ssd->midsession = midsession;
1321 * The standard panel that appears at the bottom of all panels:
1322 * Open, Cancel, Apply etc.
1324 s = ctrl_getset(b, "", "", "");
1325 ctrl_columns(s, 5, 20, 20, 20, 20, 20);
1326 ssd->okbutton = ctrl_pushbutton(s,
1327 (midsession ? "Apply" : "Open"),
1328 (char)(midsession ? 'a' : 'o'),
1330 sessionsaver_handler, P(ssd));
1331 ssd->okbutton->button.isdefault = TRUE;
1332 ssd->okbutton->generic.column = 3;
1333 ssd->cancelbutton = ctrl_pushbutton(s, "Cancel", 'c', HELPCTX(no_help),
1334 sessionsaver_handler, P(ssd));
1335 ssd->cancelbutton->button.iscancel = TRUE;
1336 ssd->cancelbutton->generic.column = 4;
1337 /* We carefully don't close the 5-column part, so that platform-
1338 * specific add-ons can put extra buttons alongside Open and Cancel. */
1341 * The Session panel.
1343 str = dupprintf("Basic options for your %s session", appname);
1344 ctrl_settitle(b, "Session", str);
1348 struct hostport *hp = (struct hostport *)
1349 ctrl_alloc(b, sizeof(struct hostport));
1351 s = ctrl_getset(b, "Session", "hostport",
1352 "Specify the destination you want to connect to");
1353 ctrl_columns(s, 2, 75, 25);
1354 c = ctrl_editbox(s, HOST_BOX_TITLE, 'n', 100,
1355 HELPCTX(session_hostname),
1356 config_host_handler, I(0), I(0));
1357 c->generic.column = 0;
1359 c = ctrl_editbox(s, PORT_BOX_TITLE, 'p', 100,
1360 HELPCTX(session_hostname),
1361 config_port_handler, I(0), I(0));
1362 c->generic.column = 1;
1364 ctrl_columns(s, 1, 100);
1366 if (!backend_from_proto(PROT_SSH)) {
1367 ctrl_radiobuttons(s, "Connection type:", NO_SHORTCUT, 3,
1368 HELPCTX(session_hostname),
1369 config_protocolbuttons_handler, P(hp),
1370 "Raw", 'w', I(PROT_RAW),
1371 "Telnet", 't', I(PROT_TELNET),
1372 "Rlogin", 'i', I(PROT_RLOGIN),
1375 ctrl_radiobuttons(s, "Connection type:", NO_SHORTCUT, 4,
1376 HELPCTX(session_hostname),
1377 config_protocolbuttons_handler, P(hp),
1378 "Raw", 'w', I(PROT_RAW),
1379 "Telnet", 't', I(PROT_TELNET),
1380 "Rlogin", 'i', I(PROT_RLOGIN),
1381 "SSH", 's', I(PROT_SSH),
1387 * The Load/Save panel is available even in mid-session.
1389 s = ctrl_getset(b, "Session", "savedsessions",
1390 midsession ? "Save the current session settings" :
1391 "Load, save or delete a stored session");
1392 ctrl_columns(s, 2, 75, 25);
1393 get_sesslist(&ssd->sesslist, TRUE);
1394 ssd->editbox = ctrl_editbox(s, "Saved Sessions", 'e', 100,
1395 HELPCTX(session_saved),
1396 sessionsaver_handler, P(ssd), P(NULL));
1397 ssd->editbox->generic.column = 0;
1398 /* Reset columns so that the buttons are alongside the list, rather
1399 * than alongside that edit box. */
1400 ctrl_columns(s, 1, 100);
1401 ctrl_columns(s, 2, 75, 25);
1402 ssd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1403 HELPCTX(session_saved),
1404 sessionsaver_handler, P(ssd));
1405 ssd->listbox->generic.column = 0;
1406 ssd->listbox->listbox.height = 7;
1408 ssd->loadbutton = ctrl_pushbutton(s, "Load", 'l',
1409 HELPCTX(session_saved),
1410 sessionsaver_handler, P(ssd));
1411 ssd->loadbutton->generic.column = 1;
1413 /* We can't offer the Load button mid-session, as it would allow the
1414 * user to load and subsequently save settings they can't see. (And
1415 * also change otherwise immutable settings underfoot; that probably
1416 * shouldn't be a problem, but.) */
1417 ssd->loadbutton = NULL;
1419 /* "Save" button is permitted mid-session. */
1420 ssd->savebutton = ctrl_pushbutton(s, "Save", 'v',
1421 HELPCTX(session_saved),
1422 sessionsaver_handler, P(ssd));
1423 ssd->savebutton->generic.column = 1;
1425 ssd->delbutton = ctrl_pushbutton(s, "Delete", 'd',
1426 HELPCTX(session_saved),
1427 sessionsaver_handler, P(ssd));
1428 ssd->delbutton->generic.column = 1;
1430 /* Disable the Delete button mid-session too, for UI consistency. */
1431 ssd->delbutton = NULL;
1433 ctrl_columns(s, 1, 100);
1435 s = ctrl_getset(b, "Session", "otheropts", NULL);
1436 ctrl_radiobuttons(s, "Close window on exit:", 'x', 4,
1437 HELPCTX(session_coe),
1438 conf_radiobutton_handler,
1439 I(CONF_close_on_exit),
1440 "Always", I(FORCE_ON),
1441 "Never", I(FORCE_OFF),
1442 "Only on clean exit", I(AUTO), NULL);
1445 * The Session/Logging panel.
1447 ctrl_settitle(b, "Session/Logging", "Options controlling session logging");
1449 s = ctrl_getset(b, "Session/Logging", "main", NULL);
1451 * The logging buttons change depending on whether SSH packet
1452 * logging can sensibly be available.
1455 const char *sshlogname, *sshrawlogname;
1456 if ((midsession && protocol == PROT_SSH) ||
1457 (!midsession && backend_from_proto(PROT_SSH))) {
1458 sshlogname = "SSH packets";
1459 sshrawlogname = "SSH packets and raw data";
1461 sshlogname = NULL; /* this will disable both buttons */
1462 sshrawlogname = NULL; /* this will just placate optimisers */
1464 ctrl_radiobuttons(s, "Session logging:", NO_SHORTCUT, 2,
1465 HELPCTX(logging_main),
1466 loggingbuttons_handler,
1468 "None", 't', I(LGTYP_NONE),
1469 "Printable output", 'p', I(LGTYP_ASCII),
1470 "All session output", 'l', I(LGTYP_DEBUG),
1471 sshlogname, 's', I(LGTYP_PACKETS),
1472 sshrawlogname, 'r', I(LGTYP_SSHRAW),
1475 ctrl_filesel(s, "Log file name:", 'f',
1476 NULL, TRUE, "Select session log file name",
1477 HELPCTX(logging_filename),
1478 conf_filesel_handler, I(CONF_logfilename));
1479 ctrl_text(s, "(Log file name can contain &Y, &M, &D for date,"
1480 " &T for time, and &H for host name)",
1481 HELPCTX(logging_filename));
1482 ctrl_radiobuttons(s, "What to do if the log file already exists:", 'e', 1,
1483 HELPCTX(logging_exists),
1484 conf_radiobutton_handler, I(CONF_logxfovr),
1485 "Always overwrite it", I(LGXF_OVR),
1486 "Always append to the end of it", I(LGXF_APN),
1487 "Ask the user every time", I(LGXF_ASK), NULL);
1488 ctrl_checkbox(s, "Flush log file frequently", 'u',
1489 HELPCTX(logging_flush),
1490 conf_checkbox_handler, I(CONF_logflush));
1492 if ((midsession && protocol == PROT_SSH) ||
1493 (!midsession && backend_from_proto(PROT_SSH))) {
1494 s = ctrl_getset(b, "Session/Logging", "ssh",
1495 "Options specific to SSH packet logging");
1496 ctrl_checkbox(s, "Omit known password fields", 'k',
1497 HELPCTX(logging_ssh_omit_password),
1498 conf_checkbox_handler, I(CONF_logomitpass));
1499 ctrl_checkbox(s, "Omit session data", 'd',
1500 HELPCTX(logging_ssh_omit_data),
1501 conf_checkbox_handler, I(CONF_logomitdata));
1505 * The Terminal panel.
1507 ctrl_settitle(b, "Terminal", "Options controlling the terminal emulation");
1509 s = ctrl_getset(b, "Terminal", "general", "Set various terminal options");
1510 ctrl_checkbox(s, "Auto wrap mode initially on", 'w',
1511 HELPCTX(terminal_autowrap),
1512 conf_checkbox_handler, I(CONF_wrap_mode));
1513 ctrl_checkbox(s, "DEC Origin Mode initially on", 'd',
1514 HELPCTX(terminal_decom),
1515 conf_checkbox_handler, I(CONF_dec_om));
1516 ctrl_checkbox(s, "Implicit CR in every LF", 'r',
1517 HELPCTX(terminal_lfhascr),
1518 conf_checkbox_handler, I(CONF_lfhascr));
1519 ctrl_checkbox(s, "Implicit LF in every CR", 'f',
1520 HELPCTX(terminal_crhaslf),
1521 conf_checkbox_handler, I(CONF_crhaslf));
1522 ctrl_checkbox(s, "Use background colour to erase screen", 'e',
1523 HELPCTX(terminal_bce),
1524 conf_checkbox_handler, I(CONF_bce));
1525 ctrl_checkbox(s, "Enable blinking text", 'n',
1526 HELPCTX(terminal_blink),
1527 conf_checkbox_handler, I(CONF_blinktext));
1528 ctrl_editbox(s, "Answerback to ^E:", 's', 100,
1529 HELPCTX(terminal_answerback),
1530 conf_editbox_handler, I(CONF_answerback), I(1));
1532 s = ctrl_getset(b, "Terminal", "ldisc", "Line discipline options");
1533 ctrl_radiobuttons(s, "Local echo:", 'l', 3,
1534 HELPCTX(terminal_localecho),
1535 conf_radiobutton_handler,I(CONF_localecho),
1537 "Force on", I(FORCE_ON),
1538 "Force off", I(FORCE_OFF), NULL);
1539 ctrl_radiobuttons(s, "Local line editing:", 't', 3,
1540 HELPCTX(terminal_localedit),
1541 conf_radiobutton_handler,I(CONF_localedit),
1543 "Force on", I(FORCE_ON),
1544 "Force off", I(FORCE_OFF), NULL);
1546 s = ctrl_getset(b, "Terminal", "printing", "Remote-controlled printing");
1547 ctrl_combobox(s, "Printer to send ANSI printer output to:", 'p', 100,
1548 HELPCTX(terminal_printing),
1549 printerbox_handler, P(NULL), P(NULL));
1552 * The Terminal/Keyboard panel.
1554 ctrl_settitle(b, "Terminal/Keyboard",
1555 "Options controlling the effects of keys");
1557 s = ctrl_getset(b, "Terminal/Keyboard", "mappings",
1558 "Change the sequences sent by:");
1559 ctrl_radiobuttons(s, "The Backspace key", 'b', 2,
1560 HELPCTX(keyboard_backspace),
1561 conf_radiobutton_handler,
1562 I(CONF_bksp_is_delete),
1563 "Control-H", I(0), "Control-? (127)", I(1), NULL);
1564 ctrl_radiobuttons(s, "The Home and End keys", 'e', 2,
1565 HELPCTX(keyboard_homeend),
1566 conf_radiobutton_handler,
1567 I(CONF_rxvt_homeend),
1568 "Standard", I(0), "rxvt", I(1), NULL);
1569 ctrl_radiobuttons(s, "The Function keys and keypad", 'f', 3,
1570 HELPCTX(keyboard_funkeys),
1571 conf_radiobutton_handler,
1573 "ESC[n~", I(0), "Linux", I(1), "Xterm R6", I(2),
1574 "VT400", I(3), "VT100+", I(4), "SCO", I(5), NULL);
1576 s = ctrl_getset(b, "Terminal/Keyboard", "appkeypad",
1577 "Application keypad settings:");
1578 ctrl_radiobuttons(s, "Initial state of cursor keys:", 'r', 3,
1579 HELPCTX(keyboard_appcursor),
1580 conf_radiobutton_handler,
1582 "Normal", I(0), "Application", I(1), NULL);
1583 ctrl_radiobuttons(s, "Initial state of numeric keypad:", 'n', 3,
1584 HELPCTX(keyboard_appkeypad),
1585 numeric_keypad_handler, P(NULL),
1586 "Normal", I(0), "Application", I(1), "NetHack", I(2),
1590 * The Terminal/Bell panel.
1592 ctrl_settitle(b, "Terminal/Bell",
1593 "Options controlling the terminal bell");
1595 s = ctrl_getset(b, "Terminal/Bell", "style", "Set the style of bell");
1596 ctrl_radiobuttons(s, "Action to happen when a bell occurs:", 'b', 1,
1597 HELPCTX(bell_style),
1598 conf_radiobutton_handler, I(CONF_beep),
1599 "None (bell disabled)", I(BELL_DISABLED),
1600 "Make default system alert sound", I(BELL_DEFAULT),
1601 "Visual bell (flash window)", I(BELL_VISUAL), NULL);
1603 s = ctrl_getset(b, "Terminal/Bell", "overload",
1604 "Control the bell overload behaviour");
1605 ctrl_checkbox(s, "Bell is temporarily disabled when over-used", 'd',
1606 HELPCTX(bell_overload),
1607 conf_checkbox_handler, I(CONF_bellovl));
1608 ctrl_editbox(s, "Over-use means this many bells...", 'm', 20,
1609 HELPCTX(bell_overload),
1610 conf_editbox_handler, I(CONF_bellovl_n), I(-1));
1611 ctrl_editbox(s, "... in this many seconds", 't', 20,
1612 HELPCTX(bell_overload),
1613 conf_editbox_handler, I(CONF_bellovl_t),
1615 ctrl_text(s, "The bell is re-enabled after a few seconds of silence.",
1616 HELPCTX(bell_overload));
1617 ctrl_editbox(s, "Seconds of silence required", 's', 20,
1618 HELPCTX(bell_overload),
1619 conf_editbox_handler, I(CONF_bellovl_s),
1623 * The Terminal/Features panel.
1625 ctrl_settitle(b, "Terminal/Features",
1626 "Enabling and disabling advanced terminal features");
1628 s = ctrl_getset(b, "Terminal/Features", "main", NULL);
1629 ctrl_checkbox(s, "Disable application cursor keys mode", 'u',
1630 HELPCTX(features_application),
1631 conf_checkbox_handler, I(CONF_no_applic_c));
1632 ctrl_checkbox(s, "Disable application keypad mode", 'k',
1633 HELPCTX(features_application),
1634 conf_checkbox_handler, I(CONF_no_applic_k));
1635 ctrl_checkbox(s, "Disable xterm-style mouse reporting", 'x',
1636 HELPCTX(features_mouse),
1637 conf_checkbox_handler, I(CONF_no_mouse_rep));
1638 ctrl_checkbox(s, "Disable remote-controlled terminal resizing", 's',
1639 HELPCTX(features_resize),
1640 conf_checkbox_handler,
1641 I(CONF_no_remote_resize));
1642 ctrl_checkbox(s, "Disable switching to alternate terminal screen", 'w',
1643 HELPCTX(features_altscreen),
1644 conf_checkbox_handler, I(CONF_no_alt_screen));
1645 ctrl_checkbox(s, "Disable remote-controlled window title changing", 't',
1646 HELPCTX(features_retitle),
1647 conf_checkbox_handler,
1648 I(CONF_no_remote_wintitle));
1649 ctrl_radiobuttons(s, "Response to remote title query (SECURITY):", 'q', 3,
1650 HELPCTX(features_qtitle),
1651 conf_radiobutton_handler,
1652 I(CONF_remote_qtitle_action),
1653 "None", I(TITLE_NONE),
1654 "Empty string", I(TITLE_EMPTY),
1655 "Window title", I(TITLE_REAL), NULL);
1656 ctrl_checkbox(s, "Disable destructive backspace on server sending ^?",'b',
1657 HELPCTX(features_dbackspace),
1658 conf_checkbox_handler, I(CONF_no_dbackspace));
1659 ctrl_checkbox(s, "Disable remote-controlled character set configuration",
1660 'r', HELPCTX(features_charset), conf_checkbox_handler,
1661 I(CONF_no_remote_charset));
1662 ctrl_checkbox(s, "Disable Arabic text shaping",
1663 'l', HELPCTX(features_arabicshaping), conf_checkbox_handler,
1664 I(CONF_arabicshaping));
1665 ctrl_checkbox(s, "Disable bidirectional text display",
1666 'd', HELPCTX(features_bidi), conf_checkbox_handler,
1672 str = dupprintf("Options controlling %s's window", appname);
1673 ctrl_settitle(b, "Window", str);
1676 s = ctrl_getset(b, "Window", "size", "Set the size of the window");
1677 ctrl_columns(s, 2, 50, 50);
1678 c = ctrl_editbox(s, "Columns", 'm', 100,
1679 HELPCTX(window_size),
1680 conf_editbox_handler, I(CONF_width), I(-1));
1681 c->generic.column = 0;
1682 c = ctrl_editbox(s, "Rows", 'r', 100,
1683 HELPCTX(window_size),
1684 conf_editbox_handler, I(CONF_height),I(-1));
1685 c->generic.column = 1;
1686 ctrl_columns(s, 1, 100);
1688 s = ctrl_getset(b, "Window", "scrollback",
1689 "Control the scrollback in the window");
1690 ctrl_editbox(s, "Lines of scrollback", 's', 50,
1691 HELPCTX(window_scrollback),
1692 conf_editbox_handler, I(CONF_savelines), I(-1));
1693 ctrl_checkbox(s, "Display scrollbar", 'd',
1694 HELPCTX(window_scrollback),
1695 conf_checkbox_handler, I(CONF_scrollbar));
1696 ctrl_checkbox(s, "Reset scrollback on keypress", 'k',
1697 HELPCTX(window_scrollback),
1698 conf_checkbox_handler, I(CONF_scroll_on_key));
1699 ctrl_checkbox(s, "Reset scrollback on display activity", 'p',
1700 HELPCTX(window_scrollback),
1701 conf_checkbox_handler, I(CONF_scroll_on_disp));
1702 ctrl_checkbox(s, "Push erased text into scrollback", 'e',
1703 HELPCTX(window_erased),
1704 conf_checkbox_handler,
1705 I(CONF_erase_to_scrollback));
1708 * The Window/Appearance panel.
1710 str = dupprintf("Configure the appearance of %s's window", appname);
1711 ctrl_settitle(b, "Window/Appearance", str);
1714 s = ctrl_getset(b, "Window/Appearance", "cursor",
1715 "Adjust the use of the cursor");
1716 ctrl_radiobuttons(s, "Cursor appearance:", NO_SHORTCUT, 3,
1717 HELPCTX(appearance_cursor),
1718 conf_radiobutton_handler,
1719 I(CONF_cursor_type),
1721 "Underline", 'u', I(1),
1722 "Vertical line", 'v', I(2), NULL);
1723 ctrl_checkbox(s, "Cursor blinks", 'b',
1724 HELPCTX(appearance_cursor),
1725 conf_checkbox_handler, I(CONF_blink_cur));
1727 s = ctrl_getset(b, "Window/Appearance", "font",
1729 ctrl_fontsel(s, "Font used in the terminal window", 'n',
1730 HELPCTX(appearance_font),
1731 conf_fontsel_handler, I(CONF_font));
1733 s = ctrl_getset(b, "Window/Appearance", "mouse",
1734 "Adjust the use of the mouse pointer");
1735 ctrl_checkbox(s, "Hide mouse pointer when typing in window", 'p',
1736 HELPCTX(appearance_hidemouse),
1737 conf_checkbox_handler, I(CONF_hide_mouseptr));
1739 s = ctrl_getset(b, "Window/Appearance", "border",
1740 "Adjust the window border");
1741 ctrl_editbox(s, "Gap between text and window edge:", 'e', 20,
1742 HELPCTX(appearance_border),
1743 conf_editbox_handler,
1744 I(CONF_window_border), I(-1));
1747 * The Window/Behaviour panel.
1749 str = dupprintf("Configure the behaviour of %s's window", appname);
1750 ctrl_settitle(b, "Window/Behaviour", str);
1753 s = ctrl_getset(b, "Window/Behaviour", "title",
1754 "Adjust the behaviour of the window title");
1755 ctrl_editbox(s, "Window title:", 't', 100,
1756 HELPCTX(appearance_title),
1757 conf_editbox_handler, I(CONF_wintitle), I(1));
1758 ctrl_checkbox(s, "Separate window and icon titles", 'i',
1759 HELPCTX(appearance_title),
1760 conf_checkbox_handler,
1761 I(CHECKBOX_INVERT | CONF_win_name_always));
1763 s = ctrl_getset(b, "Window/Behaviour", "main", NULL);
1764 ctrl_checkbox(s, "Warn before closing window", 'w',
1765 HELPCTX(behaviour_closewarn),
1766 conf_checkbox_handler, I(CONF_warn_on_close));
1769 * The Window/Translation panel.
1771 ctrl_settitle(b, "Window/Translation",
1772 "Options controlling character set translation");
1774 s = ctrl_getset(b, "Window/Translation", "trans",
1775 "Character set translation");
1776 ctrl_combobox(s, "Remote character set:",
1777 'r', 100, HELPCTX(translation_codepage),
1778 codepage_handler, P(NULL), P(NULL));
1780 s = ctrl_getset(b, "Window/Translation", "tweaks", NULL);
1781 ctrl_checkbox(s, "Treat CJK ambiguous characters as wide", 'w',
1782 HELPCTX(translation_cjk_ambig_wide),
1783 conf_checkbox_handler, I(CONF_cjk_ambig_wide));
1785 str = dupprintf("Adjust how %s handles line drawing characters", appname);
1786 s = ctrl_getset(b, "Window/Translation", "linedraw", str);
1788 ctrl_radiobuttons(s, "Handling of line drawing characters:", NO_SHORTCUT,1,
1789 HELPCTX(translation_linedraw),
1790 conf_radiobutton_handler,
1792 "Use Unicode line drawing code points",'u',I(VT_UNICODE),
1793 "Poor man's line drawing (+, - and |)",'p',I(VT_POORMAN),
1795 ctrl_checkbox(s, "Copy and paste line drawing characters as lqqqk",'d',
1796 HELPCTX(selection_linedraw),
1797 conf_checkbox_handler, I(CONF_rawcnp));
1800 * The Window/Selection panel.
1802 ctrl_settitle(b, "Window/Selection", "Options controlling copy and paste");
1804 s = ctrl_getset(b, "Window/Selection", "mouse",
1805 "Control use of mouse");
1806 ctrl_checkbox(s, "Shift overrides application's use of mouse", 'p',
1807 HELPCTX(selection_shiftdrag),
1808 conf_checkbox_handler, I(CONF_mouse_override));
1809 ctrl_radiobuttons(s,
1810 "Default selection mode (Alt+drag does the other one):",
1812 HELPCTX(selection_rect),
1813 conf_radiobutton_handler,
1814 I(CONF_rect_select),
1815 "Normal", 'n', I(0),
1816 "Rectangular block", 'r', I(1), NULL);
1818 s = ctrl_getset(b, "Window/Selection", "charclass",
1819 "Control the select-one-word-at-a-time mode");
1820 ccd = (struct charclass_data *)
1821 ctrl_alloc(b, sizeof(struct charclass_data));
1822 ccd->listbox = ctrl_listbox(s, "Character classes:", 'e',
1823 HELPCTX(selection_charclasses),
1824 charclass_handler, P(ccd));
1825 ccd->listbox->listbox.multisel = 1;
1826 ccd->listbox->listbox.ncols = 4;
1827 ccd->listbox->listbox.percentages = snewn(4, int);
1828 ccd->listbox->listbox.percentages[0] = 15;
1829 ccd->listbox->listbox.percentages[1] = 25;
1830 ccd->listbox->listbox.percentages[2] = 20;
1831 ccd->listbox->listbox.percentages[3] = 40;
1832 ctrl_columns(s, 2, 67, 33);
1833 ccd->editbox = ctrl_editbox(s, "Set to class", 't', 50,
1834 HELPCTX(selection_charclasses),
1835 charclass_handler, P(ccd), P(NULL));
1836 ccd->editbox->generic.column = 0;
1837 ccd->button = ctrl_pushbutton(s, "Set", 's',
1838 HELPCTX(selection_charclasses),
1839 charclass_handler, P(ccd));
1840 ccd->button->generic.column = 1;
1841 ctrl_columns(s, 1, 100);
1844 * The Window/Colours panel.
1846 ctrl_settitle(b, "Window/Colours", "Options controlling use of colours");
1848 s = ctrl_getset(b, "Window/Colours", "general",
1849 "General options for colour usage");
1850 ctrl_checkbox(s, "Allow terminal to specify ANSI colours", 'i',
1851 HELPCTX(colours_ansi),
1852 conf_checkbox_handler, I(CONF_ansi_colour));
1853 ctrl_checkbox(s, "Allow terminal to use xterm 256-colour mode", '2',
1854 HELPCTX(colours_xterm256), conf_checkbox_handler,
1855 I(CONF_xterm_256_colour));
1856 ctrl_radiobuttons(s, "Indicate bolded text by changing:", 'b', 3,
1857 HELPCTX(colours_bold),
1858 conf_radiobutton_handler, I(CONF_bold_style),
1864 str = dupprintf("Adjust the precise colours %s displays", appname);
1865 s = ctrl_getset(b, "Window/Colours", "adjust", str);
1867 ctrl_text(s, "Select a colour from the list, and then click the"
1868 " Modify button to change its appearance.",
1869 HELPCTX(colours_config));
1870 ctrl_columns(s, 2, 67, 33);
1871 cd = (struct colour_data *)ctrl_alloc(b, sizeof(struct colour_data));
1872 cd->listbox = ctrl_listbox(s, "Select a colour to adjust:", 'u',
1873 HELPCTX(colours_config), colour_handler, P(cd));
1874 cd->listbox->generic.column = 0;
1875 cd->listbox->listbox.height = 7;
1876 c = ctrl_text(s, "RGB value:", HELPCTX(colours_config));
1877 c->generic.column = 1;
1878 cd->redit = ctrl_editbox(s, "Red", 'r', 50, HELPCTX(colours_config),
1879 colour_handler, P(cd), P(NULL));
1880 cd->redit->generic.column = 1;
1881 cd->gedit = ctrl_editbox(s, "Green", 'n', 50, HELPCTX(colours_config),
1882 colour_handler, P(cd), P(NULL));
1883 cd->gedit->generic.column = 1;
1884 cd->bedit = ctrl_editbox(s, "Blue", 'e', 50, HELPCTX(colours_config),
1885 colour_handler, P(cd), P(NULL));
1886 cd->bedit->generic.column = 1;
1887 cd->button = ctrl_pushbutton(s, "Modify", 'm', HELPCTX(colours_config),
1888 colour_handler, P(cd));
1889 cd->button->generic.column = 1;
1890 ctrl_columns(s, 1, 100);
1893 * The Connection panel. This doesn't show up if we're in a
1894 * non-network utility such as pterm. We tell this by being
1895 * passed a protocol < 0.
1897 if (protocol >= 0) {
1898 ctrl_settitle(b, "Connection", "Options controlling the connection");
1900 s = ctrl_getset(b, "Connection", "keepalive",
1901 "Sending of null packets to keep session active");
1902 ctrl_editbox(s, "Seconds between keepalives (0 to turn off)", 'k', 20,
1903 HELPCTX(connection_keepalive),
1904 conf_editbox_handler, I(CONF_ping_interval),
1908 s = ctrl_getset(b, "Connection", "tcp",
1909 "Low-level TCP connection options");
1910 ctrl_checkbox(s, "Disable Nagle's algorithm (TCP_NODELAY option)",
1911 'n', HELPCTX(connection_nodelay),
1912 conf_checkbox_handler,
1913 I(CONF_tcp_nodelay));
1914 ctrl_checkbox(s, "Enable TCP keepalives (SO_KEEPALIVE option)",
1915 'p', HELPCTX(connection_tcpkeepalive),
1916 conf_checkbox_handler,
1917 I(CONF_tcp_keepalives));
1919 s = ctrl_getset(b, "Connection", "ipversion",
1920 "Internet protocol version");
1921 ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
1922 HELPCTX(connection_ipversion),
1923 conf_radiobutton_handler,
1924 I(CONF_addressfamily),
1925 "Auto", 'u', I(ADDRTYPE_UNSPEC),
1926 "IPv4", '4', I(ADDRTYPE_IPV4),
1927 "IPv6", '6', I(ADDRTYPE_IPV6),
1932 const char *label = backend_from_proto(PROT_SSH) ?
1933 "Logical name of remote host (e.g. for SSH key lookup):" :
1934 "Logical name of remote host:";
1935 s = ctrl_getset(b, "Connection", "identity",
1936 "Logical name of remote host");
1937 ctrl_editbox(s, label, 'm', 100,
1938 HELPCTX(connection_loghost),
1939 conf_editbox_handler, I(CONF_loghost), I(1));
1944 * A sub-panel Connection/Data, containing options that
1945 * decide on data to send to the server.
1948 ctrl_settitle(b, "Connection/Data", "Data to send to the server");
1950 s = ctrl_getset(b, "Connection/Data", "login",
1952 ctrl_editbox(s, "Auto-login username", 'u', 50,
1953 HELPCTX(connection_username),
1954 conf_editbox_handler, I(CONF_username), I(1));
1956 /* We assume the local username is sufficiently stable
1957 * to include on the dialog box. */
1958 char *user = get_username();
1959 char *userlabel = dupprintf("Use system username (%s)",
1962 ctrl_radiobuttons(s, "When username is not specified:", 'n', 4,
1963 HELPCTX(connection_username_from_env),
1964 conf_radiobutton_handler,
1965 I(CONF_username_from_env),
1972 s = ctrl_getset(b, "Connection/Data", "term",
1973 "Terminal details");
1974 ctrl_editbox(s, "Terminal-type string", 't', 50,
1975 HELPCTX(connection_termtype),
1976 conf_editbox_handler, I(CONF_termtype), I(1));
1977 ctrl_editbox(s, "Terminal speeds", 's', 50,
1978 HELPCTX(connection_termspeed),
1979 conf_editbox_handler, I(CONF_termspeed), I(1));
1981 s = ctrl_getset(b, "Connection/Data", "env",
1982 "Environment variables");
1983 ctrl_columns(s, 2, 80, 20);
1984 ed = (struct environ_data *)
1985 ctrl_alloc(b, sizeof(struct environ_data));
1986 ed->varbox = ctrl_editbox(s, "Variable", 'v', 60,
1987 HELPCTX(telnet_environ),
1988 environ_handler, P(ed), P(NULL));
1989 ed->varbox->generic.column = 0;
1990 ed->valbox = ctrl_editbox(s, "Value", 'l', 60,
1991 HELPCTX(telnet_environ),
1992 environ_handler, P(ed), P(NULL));
1993 ed->valbox->generic.column = 0;
1994 ed->addbutton = ctrl_pushbutton(s, "Add", 'd',
1995 HELPCTX(telnet_environ),
1996 environ_handler, P(ed));
1997 ed->addbutton->generic.column = 1;
1998 ed->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1999 HELPCTX(telnet_environ),
2000 environ_handler, P(ed));
2001 ed->rembutton->generic.column = 1;
2002 ctrl_columns(s, 1, 100);
2003 ed->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
2004 HELPCTX(telnet_environ),
2005 environ_handler, P(ed));
2006 ed->listbox->listbox.height = 3;
2007 ed->listbox->listbox.ncols = 2;
2008 ed->listbox->listbox.percentages = snewn(2, int);
2009 ed->listbox->listbox.percentages[0] = 30;
2010 ed->listbox->listbox.percentages[1] = 70;
2017 * The Connection/Proxy panel.
2019 ctrl_settitle(b, "Connection/Proxy",
2020 "Options controlling proxy usage");
2022 s = ctrl_getset(b, "Connection/Proxy", "basics", NULL);
2023 ctrl_radiobuttons(s, "Proxy type:", 't', 3,
2024 HELPCTX(proxy_type),
2025 conf_radiobutton_handler,
2027 "None", I(PROXY_NONE),
2028 "SOCKS 4", I(PROXY_SOCKS4),
2029 "SOCKS 5", I(PROXY_SOCKS5),
2030 "HTTP", I(PROXY_HTTP),
2031 "Telnet", I(PROXY_TELNET),
2033 ctrl_columns(s, 2, 80, 20);
2034 c = ctrl_editbox(s, "Proxy hostname", 'y', 100,
2035 HELPCTX(proxy_main),
2036 conf_editbox_handler,
2037 I(CONF_proxy_host), I(1));
2038 c->generic.column = 0;
2039 c = ctrl_editbox(s, "Port", 'p', 100,
2040 HELPCTX(proxy_main),
2041 conf_editbox_handler,
2044 c->generic.column = 1;
2045 ctrl_columns(s, 1, 100);
2046 ctrl_editbox(s, "Exclude Hosts/IPs", 'e', 100,
2047 HELPCTX(proxy_exclude),
2048 conf_editbox_handler,
2049 I(CONF_proxy_exclude_list), I(1));
2050 ctrl_checkbox(s, "Consider proxying local host connections", 'x',
2051 HELPCTX(proxy_exclude),
2052 conf_checkbox_handler,
2053 I(CONF_even_proxy_localhost));
2054 ctrl_radiobuttons(s, "Do DNS name lookup at proxy end:", 'd', 3,
2056 conf_radiobutton_handler,
2060 "Yes", I(FORCE_ON), NULL);
2061 ctrl_editbox(s, "Username", 'u', 60,
2062 HELPCTX(proxy_auth),
2063 conf_editbox_handler,
2064 I(CONF_proxy_username), I(1));
2065 c = ctrl_editbox(s, "Password", 'w', 60,
2066 HELPCTX(proxy_auth),
2067 conf_editbox_handler,
2068 I(CONF_proxy_password), I(1));
2069 c->editbox.password = 1;
2070 ctrl_editbox(s, "Telnet command", 'm', 100,
2071 HELPCTX(proxy_command),
2072 conf_editbox_handler,
2073 I(CONF_proxy_telnet_command), I(1));
2077 * The Telnet panel exists in the base config box, and in a
2078 * mid-session reconfig box _if_ we're using Telnet.
2080 if (!midsession || protocol == PROT_TELNET) {
2082 * The Connection/Telnet panel.
2084 ctrl_settitle(b, "Connection/Telnet",
2085 "Options controlling Telnet connections");
2087 s = ctrl_getset(b, "Connection/Telnet", "protocol",
2088 "Telnet protocol adjustments");
2091 ctrl_radiobuttons(s, "Handling of OLD_ENVIRON ambiguity:",
2093 HELPCTX(telnet_oldenviron),
2094 conf_radiobutton_handler,
2095 I(CONF_rfc_environ),
2096 "BSD (commonplace)", 'b', I(0),
2097 "RFC 1408 (unusual)", 'f', I(1), NULL);
2098 ctrl_radiobuttons(s, "Telnet negotiation mode:", 't', 2,
2099 HELPCTX(telnet_passive),
2100 conf_radiobutton_handler,
2101 I(CONF_passive_telnet),
2102 "Passive", I(1), "Active", I(0), NULL);
2104 ctrl_checkbox(s, "Keyboard sends Telnet special commands", 'k',
2105 HELPCTX(telnet_specialkeys),
2106 conf_checkbox_handler,
2107 I(CONF_telnet_keyboard));
2108 ctrl_checkbox(s, "Return key sends Telnet New Line instead of ^M",
2109 'm', HELPCTX(telnet_newline),
2110 conf_checkbox_handler,
2111 I(CONF_telnet_newline));
2117 * The Connection/Rlogin panel.
2119 ctrl_settitle(b, "Connection/Rlogin",
2120 "Options controlling Rlogin connections");
2122 s = ctrl_getset(b, "Connection/Rlogin", "data",
2123 "Data to send to the server");
2124 ctrl_editbox(s, "Local username:", 'l', 50,
2125 HELPCTX(rlogin_localuser),
2126 conf_editbox_handler, I(CONF_localusername), I(1));
2131 * All the SSH stuff is omitted in PuTTYtel, or in a reconfig
2132 * when we're not doing SSH.
2135 if (backend_from_proto(PROT_SSH) && (!midsession || protocol == PROT_SSH)) {
2138 * The Connection/SSH panel.
2140 ctrl_settitle(b, "Connection/SSH",
2141 "Options controlling SSH connections");
2143 /* SSH-1 or connection-sharing downstream */
2144 if (midsession && (protcfginfo == 1 || protcfginfo == -1)) {
2145 s = ctrl_getset(b, "Connection/SSH", "disclaimer", NULL);
2146 ctrl_text(s, "Nothing on this panel may be reconfigured in mid-"
2147 "session; it is only here so that sub-panels of it can "
2148 "exist without looking strange.", HELPCTX(no_help));
2153 s = ctrl_getset(b, "Connection/SSH", "data",
2154 "Data to send to the server");
2155 ctrl_editbox(s, "Remote command:", 'r', 100,
2156 HELPCTX(ssh_command),
2157 conf_editbox_handler, I(CONF_remote_cmd), I(1));
2159 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
2160 ctrl_checkbox(s, "Don't start a shell or command at all", 'n',
2161 HELPCTX(ssh_noshell),
2162 conf_checkbox_handler,
2163 I(CONF_ssh_no_shell));
2166 if (!midsession || !(protcfginfo == 1 || protcfginfo == -1)) {
2167 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
2169 ctrl_checkbox(s, "Enable compression", 'e',
2170 HELPCTX(ssh_compress),
2171 conf_checkbox_handler,
2172 I(CONF_compression));
2176 s = ctrl_getset(b, "Connection/SSH", "sharing", "Sharing an SSH connection between PuTTY tools");
2178 ctrl_checkbox(s, "Share SSH connections if possible", 's',
2180 conf_checkbox_handler,
2181 I(CONF_ssh_connection_sharing));
2183 ctrl_text(s, "Permitted roles in a shared connection:",
2184 HELPCTX(ssh_share));
2185 ctrl_checkbox(s, "Upstream (connecting to the real server)", 'u',
2187 conf_checkbox_handler,
2188 I(CONF_ssh_connection_sharing_upstream));
2189 ctrl_checkbox(s, "Downstream (connecting to the upstream PuTTY)", 'd',
2191 conf_checkbox_handler,
2192 I(CONF_ssh_connection_sharing_downstream));
2196 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
2198 ctrl_radiobuttons(s, "Preferred SSH protocol version:", NO_SHORTCUT, 4,
2199 HELPCTX(ssh_protocol),
2200 conf_radiobutton_handler,
2202 "1 only", 'l', I(0),
2205 "2 only", 'y', I(3), NULL);
2209 * The Connection/SSH/Kex panel. (Owing to repeat key
2210 * exchange, much of this is meaningful in mid-session _if_
2211 * we're using SSH-2 and are not a connection-sharing
2212 * downstream, or haven't decided yet.)
2214 if (protcfginfo != 1 && protcfginfo != -1) {
2215 ctrl_settitle(b, "Connection/SSH/Kex",
2216 "Options controlling SSH key exchange");
2218 s = ctrl_getset(b, "Connection/SSH/Kex", "main",
2219 "Key exchange algorithm options");
2220 c = ctrl_draglist(s, "Algorithm selection policy:", 's',
2221 HELPCTX(ssh_kexlist),
2222 kexlist_handler, P(NULL));
2223 c->listbox.height = 5;
2225 s = ctrl_getset(b, "Connection/SSH/Kex", "repeat",
2226 "Options controlling key re-exchange");
2228 ctrl_editbox(s, "Max minutes before rekey (0 for no limit)", 't', 20,
2229 HELPCTX(ssh_kex_repeat),
2230 conf_editbox_handler,
2231 I(CONF_ssh_rekey_time),
2233 ctrl_editbox(s, "Max data before rekey (0 for no limit)", 'x', 20,
2234 HELPCTX(ssh_kex_repeat),
2235 conf_editbox_handler,
2236 I(CONF_ssh_rekey_data),
2238 ctrl_text(s, "(Use 1M for 1 megabyte, 1G for 1 gigabyte etc)",
2239 HELPCTX(ssh_kex_repeat));
2243 * Manual host key configuration is irrelevant mid-session,
2244 * as we enforce that the host key for rekeys is the
2245 * same as that used at the start of the session.
2248 s = ctrl_getset(b, "Connection/SSH/Kex", "hostkeys",
2249 "Manually configure host keys for this connection");
2251 ctrl_columns(s, 2, 75, 25);
2252 c = ctrl_text(s, "Host keys or fingerprints to accept:",
2253 HELPCTX(ssh_kex_manual_hostkeys));
2254 c->generic.column = 0;
2255 /* You want to select from the list, _then_ hit Remove. So
2256 * tab order should be that way round. */
2257 mh = (struct manual_hostkey_data *)
2258 ctrl_alloc(b,sizeof(struct manual_hostkey_data));
2259 mh->rembutton = ctrl_pushbutton(s, "Remove", 'r',
2260 HELPCTX(ssh_kex_manual_hostkeys),
2261 manual_hostkey_handler, P(mh));
2262 mh->rembutton->generic.column = 1;
2263 mh->rembutton->generic.tabdelay = 1;
2264 mh->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
2265 HELPCTX(ssh_kex_manual_hostkeys),
2266 manual_hostkey_handler, P(mh));
2267 /* This list box can't be very tall, because there's not
2268 * much room in the pane on Windows at least. This makes
2269 * it become really unhelpful if a horizontal scrollbar
2270 * appears, so we suppress that. */
2271 mh->listbox->listbox.height = 2;
2272 mh->listbox->listbox.hscroll = FALSE;
2273 ctrl_tabdelay(s, mh->rembutton);
2274 mh->keybox = ctrl_editbox(s, "Key", 'k', 80,
2275 HELPCTX(ssh_kex_manual_hostkeys),
2276 manual_hostkey_handler, P(mh), P(NULL));
2277 mh->keybox->generic.column = 0;
2278 mh->addbutton = ctrl_pushbutton(s, "Add key", 'y',
2279 HELPCTX(ssh_kex_manual_hostkeys),
2280 manual_hostkey_handler, P(mh));
2281 mh->addbutton->generic.column = 1;
2282 ctrl_columns(s, 1, 100);
2285 if (!midsession || !(protcfginfo == 1 || protcfginfo == -1)) {
2287 * The Connection/SSH/Cipher panel.
2289 ctrl_settitle(b, "Connection/SSH/Cipher",
2290 "Options controlling SSH encryption");
2292 s = ctrl_getset(b, "Connection/SSH/Cipher",
2293 "encryption", "Encryption options");
2294 c = ctrl_draglist(s, "Encryption cipher selection policy:", 's',
2295 HELPCTX(ssh_ciphers),
2296 cipherlist_handler, P(NULL));
2297 c->listbox.height = 6;
2299 ctrl_checkbox(s, "Enable legacy use of single-DES in SSH-2", 'i',
2300 HELPCTX(ssh_ciphers),
2301 conf_checkbox_handler,
2302 I(CONF_ssh2_des_cbc));
2308 * The Connection/SSH/Auth panel.
2310 ctrl_settitle(b, "Connection/SSH/Auth",
2311 "Options controlling SSH authentication");
2313 s = ctrl_getset(b, "Connection/SSH/Auth", "main", NULL);
2314 ctrl_checkbox(s, "Bypass authentication entirely (SSH-2 only)", 'b',
2315 HELPCTX(ssh_auth_bypass),
2316 conf_checkbox_handler,
2317 I(CONF_ssh_no_userauth));
2318 ctrl_checkbox(s, "Display pre-authentication banner (SSH-2 only)",
2319 'd', HELPCTX(ssh_auth_banner),
2320 conf_checkbox_handler,
2321 I(CONF_ssh_show_banner));
2323 s = ctrl_getset(b, "Connection/SSH/Auth", "methods",
2324 "Authentication methods");
2325 ctrl_checkbox(s, "Attempt authentication using Pageant", 'p',
2326 HELPCTX(ssh_auth_pageant),
2327 conf_checkbox_handler,
2329 ctrl_checkbox(s, "Attempt TIS or CryptoCard auth (SSH-1)", 'm',
2330 HELPCTX(ssh_auth_tis),
2331 conf_checkbox_handler,
2332 I(CONF_try_tis_auth));
2333 ctrl_checkbox(s, "Attempt \"keyboard-interactive\" auth (SSH-2)",
2334 'i', HELPCTX(ssh_auth_ki),
2335 conf_checkbox_handler,
2336 I(CONF_try_ki_auth));
2338 s = ctrl_getset(b, "Connection/SSH/Auth", "params",
2339 "Authentication parameters");
2340 ctrl_checkbox(s, "Allow agent forwarding", 'f',
2341 HELPCTX(ssh_auth_agentfwd),
2342 conf_checkbox_handler, I(CONF_agentfwd));
2343 ctrl_checkbox(s, "Allow attempted changes of username in SSH-2", NO_SHORTCUT,
2344 HELPCTX(ssh_auth_changeuser),
2345 conf_checkbox_handler,
2346 I(CONF_change_username));
2347 ctrl_filesel(s, "Private key file for authentication:", 'k',
2348 FILTER_KEY_FILES, FALSE, "Select private key file",
2349 HELPCTX(ssh_auth_privkey),
2350 conf_filesel_handler, I(CONF_keyfile));
2354 * Connection/SSH/Auth/GSSAPI, which sadly won't fit on
2355 * the main Auth panel.
2357 ctrl_settitle(b, "Connection/SSH/Auth/GSSAPI",
2358 "Options controlling GSSAPI authentication");
2359 s = ctrl_getset(b, "Connection/SSH/Auth/GSSAPI", "gssapi", NULL);
2361 ctrl_checkbox(s, "Attempt GSSAPI authentication (SSH-2 only)",
2362 't', HELPCTX(ssh_gssapi),
2363 conf_checkbox_handler,
2364 I(CONF_try_gssapi_auth));
2366 ctrl_checkbox(s, "Allow GSSAPI credential delegation", 'l',
2367 HELPCTX(ssh_gssapi_delegation),
2368 conf_checkbox_handler,
2372 * GSSAPI library selection.
2375 c = ctrl_draglist(s, "Preference order for GSSAPI libraries:",
2376 'p', HELPCTX(ssh_gssapi_libraries),
2377 gsslist_handler, P(NULL));
2378 c->listbox.height = ngsslibs;
2381 * I currently assume that if more than one GSS
2382 * library option is available, then one of them is
2383 * 'user-supplied' and so we should present the
2384 * following file selector. This is at least half-
2385 * reasonable, because if we're using statically
2386 * linked GSSAPI then there will only be one option
2387 * and no way to load from a user-supplied library,
2388 * whereas if we're using dynamic libraries then
2389 * there will almost certainly be some default
2390 * option in addition to a user-supplied path. If
2391 * anyone ever ports PuTTY to a system on which
2392 * dynamic-library GSSAPI is available but there is
2393 * absolutely no consensus on where to keep the
2394 * libraries, there'll need to be a flag alongside
2395 * ngsslibs to control whether the file selector is
2399 ctrl_filesel(s, "User-supplied GSSAPI library path:", 's',
2400 FILTER_DYNLIB_FILES, FALSE, "Select library file",
2401 HELPCTX(ssh_gssapi_libraries),
2402 conf_filesel_handler,
2403 I(CONF_ssh_gss_custom));
2410 * The Connection/SSH/TTY panel.
2412 ctrl_settitle(b, "Connection/SSH/TTY", "Remote terminal settings");
2414 s = ctrl_getset(b, "Connection/SSH/TTY", "sshtty", NULL);
2415 ctrl_checkbox(s, "Don't allocate a pseudo-terminal", 'p',
2417 conf_checkbox_handler,
2420 s = ctrl_getset(b, "Connection/SSH/TTY", "ttymodes",
2422 td = (struct ttymodes_data *)
2423 ctrl_alloc(b, sizeof(struct ttymodes_data));
2424 ctrl_columns(s, 2, 75, 25);
2425 c = ctrl_text(s, "Terminal modes to send:", HELPCTX(ssh_ttymodes));
2426 c->generic.column = 0;
2427 td->rembutton = ctrl_pushbutton(s, "Remove", 'r',
2428 HELPCTX(ssh_ttymodes),
2429 ttymodes_handler, P(td));
2430 td->rembutton->generic.column = 1;
2431 td->rembutton->generic.tabdelay = 1;
2432 ctrl_columns(s, 1, 100);
2433 td->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
2434 HELPCTX(ssh_ttymodes),
2435 ttymodes_handler, P(td));
2436 td->listbox->listbox.multisel = 1;
2437 td->listbox->listbox.height = 4;
2438 td->listbox->listbox.ncols = 2;
2439 td->listbox->listbox.percentages = snewn(2, int);
2440 td->listbox->listbox.percentages[0] = 40;
2441 td->listbox->listbox.percentages[1] = 60;
2442 ctrl_tabdelay(s, td->rembutton);
2443 ctrl_columns(s, 2, 75, 25);
2444 td->modelist = ctrl_droplist(s, "Mode:", 'm', 67,
2445 HELPCTX(ssh_ttymodes),
2446 ttymodes_handler, P(td));
2447 td->modelist->generic.column = 0;
2448 td->addbutton = ctrl_pushbutton(s, "Add", 'd',
2449 HELPCTX(ssh_ttymodes),
2450 ttymodes_handler, P(td));
2451 td->addbutton->generic.column = 1;
2452 td->addbutton->generic.tabdelay = 1;
2453 ctrl_columns(s, 1, 100); /* column break */
2454 /* Bit of a hack to get the value radio buttons and
2455 * edit-box on the same row. */
2456 ctrl_columns(s, 3, 25, 50, 25);
2457 c = ctrl_text(s, "Value:", HELPCTX(ssh_ttymodes));
2458 c->generic.column = 0;
2459 td->valradio = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 2,
2460 HELPCTX(ssh_ttymodes),
2461 ttymodes_handler, P(td),
2462 "Auto", NO_SHORTCUT, P(NULL),
2463 "This:", NO_SHORTCUT, P(NULL),
2465 td->valradio->generic.column = 1;
2466 td->valbox = ctrl_editbox(s, NULL, NO_SHORTCUT, 100,
2467 HELPCTX(ssh_ttymodes),
2468 ttymodes_handler, P(td), P(NULL));
2469 td->valbox->generic.column = 2;
2470 ctrl_tabdelay(s, td->addbutton);
2476 * The Connection/SSH/X11 panel.
2478 ctrl_settitle(b, "Connection/SSH/X11",
2479 "Options controlling SSH X11 forwarding");
2481 s = ctrl_getset(b, "Connection/SSH/X11", "x11", "X11 forwarding");
2482 ctrl_checkbox(s, "Enable X11 forwarding", 'e',
2483 HELPCTX(ssh_tunnels_x11),
2484 conf_checkbox_handler,I(CONF_x11_forward));
2485 ctrl_editbox(s, "X display location", 'x', 50,
2486 HELPCTX(ssh_tunnels_x11),
2487 conf_editbox_handler, I(CONF_x11_display), I(1));
2488 ctrl_radiobuttons(s, "Remote X11 authentication protocol", 'u', 2,
2489 HELPCTX(ssh_tunnels_x11auth),
2490 conf_radiobutton_handler,
2492 "MIT-Magic-Cookie-1", I(X11_MIT),
2493 "XDM-Authorization-1", I(X11_XDM), NULL);
2497 * The Tunnels panel _is_ still available in mid-session.
2499 ctrl_settitle(b, "Connection/SSH/Tunnels",
2500 "Options controlling SSH port forwarding");
2502 s = ctrl_getset(b, "Connection/SSH/Tunnels", "portfwd",
2504 ctrl_checkbox(s, "Local ports accept connections from other hosts",'t',
2505 HELPCTX(ssh_tunnels_portfwd_localhost),
2506 conf_checkbox_handler,
2507 I(CONF_lport_acceptall));
2508 ctrl_checkbox(s, "Remote ports do the same (SSH-2 only)", 'p',
2509 HELPCTX(ssh_tunnels_portfwd_localhost),
2510 conf_checkbox_handler,
2511 I(CONF_rport_acceptall));
2513 ctrl_columns(s, 3, 55, 20, 25);
2514 c = ctrl_text(s, "Forwarded ports:", HELPCTX(ssh_tunnels_portfwd));
2515 c->generic.column = COLUMN_FIELD(0,2);
2516 /* You want to select from the list, _then_ hit Remove. So tab order
2517 * should be that way round. */
2518 pfd = (struct portfwd_data *)ctrl_alloc(b,sizeof(struct portfwd_data));
2519 pfd->rembutton = ctrl_pushbutton(s, "Remove", 'r',
2520 HELPCTX(ssh_tunnels_portfwd),
2521 portfwd_handler, P(pfd));
2522 pfd->rembutton->generic.column = 2;
2523 pfd->rembutton->generic.tabdelay = 1;
2524 pfd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
2525 HELPCTX(ssh_tunnels_portfwd),
2526 portfwd_handler, P(pfd));
2527 pfd->listbox->listbox.height = 3;
2528 pfd->listbox->listbox.ncols = 2;
2529 pfd->listbox->listbox.percentages = snewn(2, int);
2530 pfd->listbox->listbox.percentages[0] = 20;
2531 pfd->listbox->listbox.percentages[1] = 80;
2532 ctrl_tabdelay(s, pfd->rembutton);
2533 ctrl_text(s, "Add new forwarded port:", HELPCTX(ssh_tunnels_portfwd));
2534 /* You want to enter source, destination and type, _then_ hit Add.
2535 * Again, we adjust the tab order to reflect this. */
2536 pfd->addbutton = ctrl_pushbutton(s, "Add", 'd',
2537 HELPCTX(ssh_tunnels_portfwd),
2538 portfwd_handler, P(pfd));
2539 pfd->addbutton->generic.column = 2;
2540 pfd->addbutton->generic.tabdelay = 1;
2541 pfd->sourcebox = ctrl_editbox(s, "Source port", 's', 40,
2542 HELPCTX(ssh_tunnels_portfwd),
2543 portfwd_handler, P(pfd), P(NULL));
2544 pfd->sourcebox->generic.column = 0;
2545 pfd->destbox = ctrl_editbox(s, "Destination", 'i', 67,
2546 HELPCTX(ssh_tunnels_portfwd),
2547 portfwd_handler, P(pfd), P(NULL));
2548 pfd->direction = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
2549 HELPCTX(ssh_tunnels_portfwd),
2550 portfwd_handler, P(pfd),
2551 "Local", 'l', P(NULL),
2552 "Remote", 'm', P(NULL),
2553 "Dynamic", 'y', P(NULL),
2556 pfd->addressfamily =
2557 ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
2558 HELPCTX(ssh_tunnels_portfwd_ipversion),
2559 portfwd_handler, P(pfd),
2560 "Auto", 'u', I(ADDRTYPE_UNSPEC),
2561 "IPv4", '4', I(ADDRTYPE_IPV4),
2562 "IPv6", '6', I(ADDRTYPE_IPV6),
2565 ctrl_tabdelay(s, pfd->addbutton);
2566 ctrl_columns(s, 1, 100);
2570 * The Connection/SSH/Bugs panels.
2572 ctrl_settitle(b, "Connection/SSH/Bugs",
2573 "Workarounds for SSH server bugs");
2575 s = ctrl_getset(b, "Connection/SSH/Bugs", "main",
2576 "Detection of known bugs in SSH servers");
2577 ctrl_droplist(s, "Chokes on SSH-1 ignore messages", 'i', 20,
2578 HELPCTX(ssh_bugs_ignore1),
2579 sshbug_handler, I(CONF_sshbug_ignore1));
2580 ctrl_droplist(s, "Refuses all SSH-1 password camouflage", 's', 20,
2581 HELPCTX(ssh_bugs_plainpw1),
2582 sshbug_handler, I(CONF_sshbug_plainpw1));
2583 ctrl_droplist(s, "Chokes on SSH-1 RSA authentication", 'r', 20,
2584 HELPCTX(ssh_bugs_rsa1),
2585 sshbug_handler, I(CONF_sshbug_rsa1));
2586 ctrl_droplist(s, "Chokes on SSH-2 ignore messages", '2', 20,
2587 HELPCTX(ssh_bugs_ignore2),
2588 sshbug_handler, I(CONF_sshbug_ignore2));
2589 ctrl_droplist(s, "Chokes on PuTTY's SSH-2 'winadj' requests", 'j',
2590 20, HELPCTX(ssh_bugs_winadj),
2591 sshbug_handler, I(CONF_sshbug_winadj));
2592 ctrl_droplist(s, "Miscomputes SSH-2 HMAC keys", 'm', 20,
2593 HELPCTX(ssh_bugs_hmac2),
2594 sshbug_handler, I(CONF_sshbug_hmac2));
2595 ctrl_droplist(s, "Miscomputes SSH-2 encryption keys", 'e', 20,
2596 HELPCTX(ssh_bugs_derivekey2),
2597 sshbug_handler, I(CONF_sshbug_derivekey2));
2599 ctrl_settitle(b, "Connection/SSH/More bugs",
2600 "Further workarounds for SSH server bugs");
2602 s = ctrl_getset(b, "Connection/SSH/More bugs", "main",
2603 "Detection of known bugs in SSH servers");
2604 ctrl_droplist(s, "Requires padding on SSH-2 RSA signatures", 'p', 20,
2605 HELPCTX(ssh_bugs_rsapad2),
2606 sshbug_handler, I(CONF_sshbug_rsapad2));
2607 ctrl_droplist(s, "Misuses the session ID in SSH-2 PK auth", 'n', 20,
2608 HELPCTX(ssh_bugs_pksessid2),
2609 sshbug_handler, I(CONF_sshbug_pksessid2));
2610 ctrl_droplist(s, "Handles SSH-2 key re-exchange badly", 'k', 20,
2611 HELPCTX(ssh_bugs_rekey2),
2612 sshbug_handler, I(CONF_sshbug_rekey2));
2613 ctrl_droplist(s, "Ignores SSH-2 maximum packet size", 'x', 20,
2614 HELPCTX(ssh_bugs_maxpkt2),
2615 sshbug_handler, I(CONF_sshbug_maxpkt2));
2616 ctrl_droplist(s, "Only supports pre-RFC4419 SSH-2 DH GEX", 'd', 20,
2617 HELPCTX(ssh_bugs_oldgex2),
2618 sshbug_handler, I(CONF_sshbug_oldgex2));
2619 ctrl_droplist(s, "Replies to requests on closed channels", 'q', 20,
2620 HELPCTX(ssh_bugs_chanreq),
2621 sshbug_handler, I(CONF_sshbug_chanreq));