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
) {
137 dlg_filesel_get(ctrl
, dlg
, &filename
);
138 conf_set_filename(conf
, key
, &filename
);
139 /* If Filenames ever become dynamic, free this one. */
143 void conf_fontsel_handler(union control
*ctrl
, void *dlg
,
144 void *data
, int event
)
146 int key
= ctrl
->fontselect
.context
.i
;
147 Conf
*conf
= (Conf
*)data
;
149 if (event
== EVENT_REFRESH
) {
150 dlg_fontsel_set(ctrl
, dlg
, *conf_get_fontspec(conf
, key
));
151 } else if (event
== EVENT_VALCHANGE
) {
153 dlg_fontsel_get(ctrl
, dlg
, &fontspec
);
154 conf_set_fontspec(conf
, key
, &fontspec
);
155 /* If FontSpecs ever become dynamic, free this one. */
159 static void config_host_handler(union control
*ctrl
, void *dlg
,
160 void *data
, int event
)
162 Conf
*conf
= (Conf
*)data
;
165 * This function works just like the standard edit box handler,
166 * only it has to choose the control's label and text from two
167 * different places depending on the protocol.
169 if (event
== EVENT_REFRESH
) {
170 if (conf_get_int(conf
, CONF_protocol
) == PROT_SERIAL
) {
172 * This label text is carefully chosen to contain an n,
173 * since that's the shortcut for the host name control.
175 dlg_label_change(ctrl
, dlg
, "Serial line");
176 dlg_editbox_set(ctrl
, dlg
, conf_get_str(conf
, CONF_serline
));
178 dlg_label_change(ctrl
, dlg
, HOST_BOX_TITLE
);
179 dlg_editbox_set(ctrl
, dlg
, conf_get_str(conf
, CONF_host
));
181 } else if (event
== EVENT_VALCHANGE
) {
182 char *s
= dlg_editbox_get(ctrl
, dlg
);
183 if (conf_get_int(conf
, CONF_protocol
) == PROT_SERIAL
)
184 conf_set_str(conf
, CONF_serline
, s
);
186 conf_set_str(conf
, CONF_host
, s
);
191 static void config_port_handler(union control
*ctrl
, void *dlg
,
192 void *data
, int event
)
194 Conf
*conf
= (Conf
*)data
;
198 * This function works similarly to the standard edit box handler,
199 * only it has to choose the control's label and text from two
200 * different places depending on the protocol.
202 if (event
== EVENT_REFRESH
) {
203 if (conf_get_int(conf
, CONF_protocol
) == PROT_SERIAL
) {
205 * This label text is carefully chosen to contain a p,
206 * since that's the shortcut for the port control.
208 dlg_label_change(ctrl
, dlg
, "Speed");
209 sprintf(buf
, "%d", conf_get_int(conf
, CONF_serspeed
));
211 dlg_label_change(ctrl
, dlg
, PORT_BOX_TITLE
);
212 if (conf_get_int(conf
, CONF_port
) != 0)
213 sprintf(buf
, "%d", conf_get_int(conf
, CONF_port
));
215 /* Display an (invalid) port of 0 as blank */
218 dlg_editbox_set(ctrl
, dlg
, buf
);
219 } else if (event
== EVENT_VALCHANGE
) {
220 char *s
= dlg_editbox_get(ctrl
, dlg
);
224 if (conf_get_int(conf
, CONF_protocol
) == PROT_SERIAL
)
225 conf_set_int(conf
, CONF_serspeed
, i
);
227 conf_set_int(conf
, CONF_port
, i
);
232 union control
*host
, *port
;
236 * We export this function so that platform-specific config
237 * routines can use it to conveniently identify the protocol radio
238 * buttons in order to add to them.
240 void config_protocolbuttons_handler(union control
*ctrl
, void *dlg
,
241 void *data
, int event
)
244 Conf
*conf
= (Conf
*)data
;
245 struct hostport
*hp
= (struct hostport
*)ctrl
->radio
.context
.p
;
248 * This function works just like the standard radio-button
249 * handler, except that it also has to change the setting of
250 * the port box, and refresh both host and port boxes when. We
251 * expect the context parameter to point at a hostport
252 * structure giving the `union control's for both.
254 if (event
== EVENT_REFRESH
) {
255 int protocol
= conf_get_int(conf
, CONF_protocol
);
256 for (button
= 0; button
< ctrl
->radio
.nbuttons
; button
++)
257 if (protocol
== ctrl
->radio
.buttondata
[button
].i
)
259 /* We expected that `break' to happen, in all circumstances. */
260 assert(button
< ctrl
->radio
.nbuttons
);
261 dlg_radiobutton_set(ctrl
, dlg
, button
);
262 } else if (event
== EVENT_VALCHANGE
) {
263 int oldproto
= conf_get_int(conf
, CONF_protocol
);
266 button
= dlg_radiobutton_get(ctrl
, dlg
);
267 assert(button
>= 0 && button
< ctrl
->radio
.nbuttons
);
268 newproto
= ctrl
->radio
.buttondata
[button
].i
;
269 conf_set_int(conf
, CONF_protocol
, newproto
);
271 if (oldproto
!= newproto
) {
272 Backend
*ob
= backend_from_proto(oldproto
);
273 Backend
*nb
= backend_from_proto(newproto
);
276 /* Iff the user hasn't changed the port from the old protocol's
277 * default, update it with the new protocol's default.
278 * (This includes a "default" of 0, implying that there is no
279 * sensible default for that protocol; in this case it's
280 * displayed as a blank.)
281 * This helps with the common case of tabbing through the
282 * controls in order and setting a non-default port before
283 * getting to the protocol; we want that non-default port
284 * to be preserved. */
285 port
= conf_get_int(conf
, CONF_port
);
286 if (port
== ob
->default_port
)
287 conf_set_int(conf
, CONF_port
, nb
->default_port
);
289 dlg_refresh(hp
->host
, dlg
);
290 dlg_refresh(hp
->port
, dlg
);
294 static void loggingbuttons_handler(union control
*ctrl
, void *dlg
,
295 void *data
, int event
)
298 Conf
*conf
= (Conf
*)data
;
299 /* This function works just like the standard radio-button handler,
300 * but it has to fall back to "no logging" in situations where the
301 * configured logging type isn't applicable.
303 if (event
== EVENT_REFRESH
) {
304 int logtype
= conf_get_int(conf
, CONF_logtype
);
306 for (button
= 0; button
< ctrl
->radio
.nbuttons
; button
++)
307 if (logtype
== ctrl
->radio
.buttondata
[button
].i
)
310 /* We fell off the end, so we lack the configured logging type */
311 if (button
== ctrl
->radio
.nbuttons
) {
313 conf_set_int(conf
, CONF_logtype
, LGTYP_NONE
);
315 dlg_radiobutton_set(ctrl
, dlg
, button
);
316 } else if (event
== EVENT_VALCHANGE
) {
317 button
= dlg_radiobutton_get(ctrl
, dlg
);
318 assert(button
>= 0 && button
< ctrl
->radio
.nbuttons
);
319 conf_set_int(conf
, CONF_logtype
, ctrl
->radio
.buttondata
[button
].i
);
323 static void numeric_keypad_handler(union control
*ctrl
, void *dlg
,
324 void *data
, int event
)
327 Conf
*conf
= (Conf
*)data
;
329 * This function works much like the standard radio button
330 * handler, but it has to handle two fields in Conf.
332 if (event
== EVENT_REFRESH
) {
333 if (conf_get_int(conf
, CONF_nethack_keypad
))
335 else if (conf_get_int(conf
, CONF_app_keypad
))
339 assert(button
< ctrl
->radio
.nbuttons
);
340 dlg_radiobutton_set(ctrl
, dlg
, button
);
341 } else if (event
== EVENT_VALCHANGE
) {
342 button
= dlg_radiobutton_get(ctrl
, dlg
);
343 assert(button
>= 0 && button
< ctrl
->radio
.nbuttons
);
345 conf_set_int(conf
, CONF_app_keypad
, FALSE
);
346 conf_set_int(conf
, CONF_nethack_keypad
, TRUE
);
348 conf_set_int(conf
, CONF_app_keypad
, (button
!= 0));
349 conf_set_int(conf
, CONF_nethack_keypad
, FALSE
);
354 static void cipherlist_handler(union control
*ctrl
, void *dlg
,
355 void *data
, int event
)
357 Conf
*conf
= (Conf
*)data
;
358 if (event
== EVENT_REFRESH
) {
361 static const struct { char *s
; int c
; } ciphers
[] = {
362 { "3DES", CIPHER_3DES
},
363 { "Blowfish", CIPHER_BLOWFISH
},
364 { "DES", CIPHER_DES
},
365 { "AES (SSH-2 only)", CIPHER_AES
},
366 { "Arcfour (SSH-2 only)", CIPHER_ARCFOUR
},
367 { "-- warn below here --", CIPHER_WARN
}
370 /* Set up the "selected ciphers" box. */
371 /* (cipherlist assumed to contain all ciphers) */
372 dlg_update_start(ctrl
, dlg
);
373 dlg_listbox_clear(ctrl
, dlg
);
374 for (i
= 0; i
< CIPHER_MAX
; i
++) {
375 int c
= conf_get_int_int(conf
, CONF_ssh_cipherlist
, i
);
378 for (j
= 0; j
< (sizeof ciphers
) / (sizeof ciphers
[0]); j
++) {
379 if (ciphers
[j
].c
== c
) {
384 dlg_listbox_addwithid(ctrl
, dlg
, cstr
, c
);
386 dlg_update_done(ctrl
, dlg
);
388 } else if (event
== EVENT_VALCHANGE
) {
391 /* Update array to match the list box. */
392 for (i
=0; i
< CIPHER_MAX
; i
++)
393 conf_set_int_int(conf
, CONF_ssh_cipherlist
, i
,
394 dlg_listbox_getid(ctrl
, dlg
, i
));
399 static void gsslist_handler(union control
*ctrl
, void *dlg
,
400 void *data
, int event
)
402 Conf
*conf
= (Conf
*)data
;
403 if (event
== EVENT_REFRESH
) {
406 dlg_update_start(ctrl
, dlg
);
407 dlg_listbox_clear(ctrl
, dlg
);
408 for (i
= 0; i
< ngsslibs
; i
++) {
409 int id
= conf_get_int_int(conf
, CONF_ssh_gsslist
, i
);
410 assert(id
>= 0 && id
< ngsslibs
);
411 dlg_listbox_addwithid(ctrl
, dlg
, gsslibnames
[id
], id
);
413 dlg_update_done(ctrl
, dlg
);
415 } else if (event
== EVENT_VALCHANGE
) {
418 /* Update array to match the list box. */
419 for (i
=0; i
< ngsslibs
; i
++)
420 conf_set_int_int(conf
, CONF_ssh_gsslist
, i
,
421 dlg_listbox_getid(ctrl
, dlg
, i
));
426 static void kexlist_handler(union control
*ctrl
, void *dlg
,
427 void *data
, int event
)
429 Conf
*conf
= (Conf
*)data
;
430 if (event
== EVENT_REFRESH
) {
433 static const struct { char *s
; int k
; } kexes
[] = {
434 { "Diffie-Hellman group 1", KEX_DHGROUP1
},
435 { "Diffie-Hellman group 14", KEX_DHGROUP14
},
436 { "Diffie-Hellman group exchange", KEX_DHGEX
},
437 { "RSA-based key exchange", KEX_RSA
},
438 { "-- warn below here --", KEX_WARN
}
441 /* Set up the "kex preference" box. */
442 /* (kexlist assumed to contain all algorithms) */
443 dlg_update_start(ctrl
, dlg
);
444 dlg_listbox_clear(ctrl
, dlg
);
445 for (i
= 0; i
< KEX_MAX
; i
++) {
446 int k
= conf_get_int_int(conf
, CONF_ssh_kexlist
, i
);
449 for (j
= 0; j
< (sizeof kexes
) / (sizeof kexes
[0]); j
++) {
450 if (kexes
[j
].k
== k
) {
455 dlg_listbox_addwithid(ctrl
, dlg
, kstr
, k
);
457 dlg_update_done(ctrl
, dlg
);
459 } else if (event
== EVENT_VALCHANGE
) {
462 /* Update array to match the list box. */
463 for (i
=0; i
< KEX_MAX
; i
++)
464 conf_set_int_int(conf
, CONF_ssh_kexlist
, i
,
465 dlg_listbox_getid(ctrl
, dlg
, i
));
469 static void printerbox_handler(union control
*ctrl
, void *dlg
,
470 void *data
, int event
)
472 Conf
*conf
= (Conf
*)data
;
473 if (event
== EVENT_REFRESH
) {
478 dlg_update_start(ctrl
, dlg
);
480 * Some backends may wish to disable the drop-down list on
481 * this edit box. Be prepared for this.
483 if (ctrl
->editbox
.has_list
) {
484 dlg_listbox_clear(ctrl
, dlg
);
485 dlg_listbox_add(ctrl
, dlg
, PRINTER_DISABLED_STRING
);
486 pe
= printer_start_enum(&nprinters
);
487 for (i
= 0; i
< nprinters
; i
++)
488 dlg_listbox_add(ctrl
, dlg
, printer_get_name(pe
, i
));
489 printer_finish_enum(pe
);
491 printer
= conf_get_str(conf
, CONF_printer
);
493 printer
= PRINTER_DISABLED_STRING
;
494 dlg_editbox_set(ctrl
, dlg
, printer
);
495 dlg_update_done(ctrl
, dlg
);
496 } else if (event
== EVENT_VALCHANGE
) {
497 char *printer
= dlg_editbox_get(ctrl
, dlg
);
498 if (!strcmp(printer
, PRINTER_DISABLED_STRING
))
500 conf_set_str(conf
, CONF_printer
, printer
);
505 static void codepage_handler(union control
*ctrl
, void *dlg
,
506 void *data
, int event
)
508 Conf
*conf
= (Conf
*)data
;
509 if (event
== EVENT_REFRESH
) {
511 const char *cp
, *thiscp
;
512 dlg_update_start(ctrl
, dlg
);
513 thiscp
= cp_name(decode_codepage(conf_get_str(conf
,
514 CONF_line_codepage
)));
515 dlg_listbox_clear(ctrl
, dlg
);
516 for (i
= 0; (cp
= cp_enumerate(i
)) != NULL
; i
++)
517 dlg_listbox_add(ctrl
, dlg
, cp
);
518 dlg_editbox_set(ctrl
, dlg
, thiscp
);
519 conf_set_str(conf
, CONF_line_codepage
, thiscp
);
520 dlg_update_done(ctrl
, dlg
);
521 } else if (event
== EVENT_VALCHANGE
) {
522 char *codepage
= dlg_editbox_get(ctrl
, dlg
);
523 conf_set_str(conf
, CONF_line_codepage
,
524 cp_name(decode_codepage(codepage
)));
529 static void sshbug_handler(union control
*ctrl
, void *dlg
,
530 void *data
, int event
)
532 Conf
*conf
= (Conf
*)data
;
533 if (event
== EVENT_REFRESH
) {
534 dlg_update_start(ctrl
, dlg
);
535 dlg_listbox_clear(ctrl
, dlg
);
536 dlg_listbox_addwithid(ctrl
, dlg
, "Auto", AUTO
);
537 dlg_listbox_addwithid(ctrl
, dlg
, "Off", FORCE_OFF
);
538 dlg_listbox_addwithid(ctrl
, dlg
, "On", FORCE_ON
);
539 switch (conf_get_int(conf
, ctrl
->listbox
.context
.i
)) {
540 case AUTO
: dlg_listbox_select(ctrl
, dlg
, 0); break;
541 case FORCE_OFF
: dlg_listbox_select(ctrl
, dlg
, 1); break;
542 case FORCE_ON
: dlg_listbox_select(ctrl
, dlg
, 2); break;
544 dlg_update_done(ctrl
, dlg
);
545 } else if (event
== EVENT_SELCHANGE
) {
546 int i
= dlg_listbox_index(ctrl
, dlg
);
550 i
= dlg_listbox_getid(ctrl
, dlg
, i
);
551 conf_set_int(conf
, ctrl
->listbox
.context
.i
, i
);
555 #define SAVEDSESSION_LEN 2048
557 struct sessionsaver_data
{
558 union control
*editbox
, *listbox
, *loadbutton
, *savebutton
, *delbutton
;
559 union control
*okbutton
, *cancelbutton
;
560 struct sesslist sesslist
;
565 * Helper function to load the session selected in the list box, if
566 * any, as this is done in more than one place below. Returns 0 for
569 static int load_selected_session(struct sessionsaver_data
*ssd
,
571 void *dlg
, Conf
*conf
, int *maybe_launch
)
573 int i
= dlg_listbox_index(ssd
->listbox
, dlg
);
579 isdef
= !strcmp(ssd
->sesslist
.sessions
[i
], "Default Settings");
580 load_settings(ssd
->sesslist
.sessions
[i
], conf
);
582 strncpy(savedsession
, ssd
->sesslist
.sessions
[i
],
584 savedsession
[SAVEDSESSION_LEN
-1] = '\0';
586 *maybe_launch
= TRUE
;
588 savedsession
[0] = '\0';
590 *maybe_launch
= FALSE
;
592 dlg_refresh(NULL
, dlg
);
593 /* Restore the selection, which might have been clobbered by
594 * changing the value of the edit box. */
595 dlg_listbox_select(ssd
->listbox
, dlg
, i
);
599 static void sessionsaver_handler(union control
*ctrl
, void *dlg
,
600 void *data
, int event
)
602 Conf
*conf
= (Conf
*)data
;
603 struct sessionsaver_data
*ssd
=
604 (struct sessionsaver_data
*)ctrl
->generic
.context
.p
;
608 * The first time we're called in a new dialog, we must
609 * allocate space to store the current contents of the saved
610 * session edit box (since it must persist even when we switch
611 * panels, but is not part of the Conf).
613 * FIXME: this is disgusting, and we'd do much better to have
614 * the persistent storage be dynamically allocated and get rid
615 * of the arbitrary limit SAVEDSESSION_LEN. To do that would
616 * require a means of making sure the memory gets freed at the
617 * appropriate moment.
621 } else if (!dlg_get_privdata(ssd
->editbox
, dlg
)) {
622 savedsession
= (char *)
623 dlg_alloc_privdata(ssd
->editbox
, dlg
, SAVEDSESSION_LEN
);
624 savedsession
[0] = '\0';
626 savedsession
= dlg_get_privdata(ssd
->editbox
, dlg
);
629 if (event
== EVENT_REFRESH
) {
630 if (ctrl
== ssd
->editbox
) {
631 dlg_editbox_set(ctrl
, dlg
, savedsession
);
632 } else if (ctrl
== ssd
->listbox
) {
634 dlg_update_start(ctrl
, dlg
);
635 dlg_listbox_clear(ctrl
, dlg
);
636 for (i
= 0; i
< ssd
->sesslist
.nsessions
; i
++)
637 dlg_listbox_add(ctrl
, dlg
, ssd
->sesslist
.sessions
[i
]);
638 dlg_update_done(ctrl
, dlg
);
640 } else if (event
== EVENT_VALCHANGE
) {
641 int top
, bottom
, halfway
, i
;
642 if (ctrl
== ssd
->editbox
) {
643 char *tmp
= dlg_editbox_get(ctrl
, dlg
);
644 strncpy(savedsession
, tmp
, SAVEDSESSION_LEN
);
646 top
= ssd
->sesslist
.nsessions
;
648 while (top
-bottom
> 1) {
649 halfway
= (top
+bottom
)/2;
650 i
= strcmp(savedsession
, ssd
->sesslist
.sessions
[halfway
]);
657 if (top
== ssd
->sesslist
.nsessions
) {
660 dlg_listbox_select(ssd
->listbox
, dlg
, top
);
662 } else if (event
== EVENT_ACTION
) {
664 if (!ssd
->midsession
&&
665 (ctrl
== ssd
->listbox
||
666 (ssd
->loadbutton
&& ctrl
== ssd
->loadbutton
))) {
668 * The user has double-clicked a session, or hit Load.
669 * We must load the selected session, and then
670 * terminate the configuration dialog _if_ there was a
671 * double-click on the list box _and_ that session
672 * contains a hostname.
674 if (load_selected_session(ssd
, savedsession
, dlg
, conf
, &mbl
) &&
675 (mbl
&& ctrl
== ssd
->listbox
&& conf_launchable(conf
))) {
676 dlg_end(dlg
, 1); /* it's all over, and succeeded */
678 } else if (ctrl
== ssd
->savebutton
) {
679 int isdef
= !strcmp(savedsession
, "Default Settings");
680 if (!savedsession
[0]) {
681 int i
= dlg_listbox_index(ssd
->listbox
, dlg
);
686 isdef
= !strcmp(ssd
->sesslist
.sessions
[i
], "Default Settings");
688 strncpy(savedsession
, ssd
->sesslist
.sessions
[i
],
690 savedsession
[SAVEDSESSION_LEN
-1] = '\0';
692 savedsession
[0] = '\0';
696 char *errmsg
= save_settings(savedsession
, conf
);
698 dlg_error_msg(dlg
, errmsg
);
702 get_sesslist(&ssd
->sesslist
, FALSE
);
703 get_sesslist(&ssd
->sesslist
, TRUE
);
704 dlg_refresh(ssd
->editbox
, dlg
);
705 dlg_refresh(ssd
->listbox
, dlg
);
706 } else if (!ssd
->midsession
&&
707 ssd
->delbutton
&& ctrl
== ssd
->delbutton
) {
708 int i
= dlg_listbox_index(ssd
->listbox
, dlg
);
712 del_settings(ssd
->sesslist
.sessions
[i
]);
713 get_sesslist(&ssd
->sesslist
, FALSE
);
714 get_sesslist(&ssd
->sesslist
, TRUE
);
715 dlg_refresh(ssd
->listbox
, dlg
);
717 } else if (ctrl
== ssd
->okbutton
) {
718 if (ssd
->midsession
) {
719 /* In a mid-session Change Settings, Apply is always OK. */
724 * Annoying special case. If the `Open' button is
725 * pressed while no host name is currently set, _and_
726 * the session list previously had the focus, _and_
727 * there was a session selected in that which had a
728 * valid host name in it, then load it and go.
730 if (dlg_last_focused(ctrl
, dlg
) == ssd
->listbox
&&
731 !conf_launchable(conf
)) {
732 Conf
*conf2
= conf_new();
734 if (!load_selected_session(ssd
, savedsession
, dlg
,
740 /* If at this point we have a valid session, go! */
741 if (mbl
&& conf_launchable(conf2
)) {
742 conf_copy_into(conf
, conf2
);
752 * Otherwise, do the normal thing: if we have a valid
753 * session, get going.
755 if (conf_launchable(conf
)) {
759 } else if (ctrl
== ssd
->cancelbutton
) {
765 struct charclass_data
{
766 union control
*listbox
, *editbox
, *button
;
769 static void charclass_handler(union control
*ctrl
, void *dlg
,
770 void *data
, int event
)
772 Conf
*conf
= (Conf
*)data
;
773 struct charclass_data
*ccd
=
774 (struct charclass_data
*)ctrl
->generic
.context
.p
;
776 if (event
== EVENT_REFRESH
) {
777 if (ctrl
== ccd
->listbox
) {
779 dlg_update_start(ctrl
, dlg
);
780 dlg_listbox_clear(ctrl
, dlg
);
781 for (i
= 0; i
< 128; i
++) {
783 sprintf(str
, "%d\t(0x%02X)\t%c\t%d", i
, i
,
784 (i
>= 0x21 && i
!= 0x7F) ? i
: ' ',
785 conf_get_int_int(conf
, CONF_wordness
, i
));
786 dlg_listbox_add(ctrl
, dlg
, str
);
788 dlg_update_done(ctrl
, dlg
);
790 } else if (event
== EVENT_ACTION
) {
791 if (ctrl
== ccd
->button
) {
794 str
= dlg_editbox_get(ccd
->editbox
, dlg
);
797 for (i
= 0; i
< 128; i
++) {
798 if (dlg_listbox_issel(ccd
->listbox
, dlg
, i
))
799 conf_set_int_int(conf
, CONF_wordness
, i
, n
);
801 dlg_refresh(ccd
->listbox
, dlg
);
807 union control
*listbox
, *redit
, *gedit
, *bedit
, *button
;
810 static const char *const colours
[] = {
811 "Default Foreground", "Default Bold Foreground",
812 "Default Background", "Default Bold Background",
813 "Cursor Text", "Cursor Colour",
814 "ANSI Black", "ANSI Black Bold",
815 "ANSI Red", "ANSI Red Bold",
816 "ANSI Green", "ANSI Green Bold",
817 "ANSI Yellow", "ANSI Yellow Bold",
818 "ANSI Blue", "ANSI Blue Bold",
819 "ANSI Magenta", "ANSI Magenta Bold",
820 "ANSI Cyan", "ANSI Cyan Bold",
821 "ANSI White", "ANSI White Bold"
824 static void colour_handler(union control
*ctrl
, void *dlg
,
825 void *data
, int event
)
827 Conf
*conf
= (Conf
*)data
;
828 struct colour_data
*cd
=
829 (struct colour_data
*)ctrl
->generic
.context
.p
;
830 int update
= FALSE
, clear
= FALSE
, r
, g
, b
;
832 if (event
== EVENT_REFRESH
) {
833 if (ctrl
== cd
->listbox
) {
835 dlg_update_start(ctrl
, dlg
);
836 dlg_listbox_clear(ctrl
, dlg
);
837 for (i
= 0; i
< lenof(colours
); i
++)
838 dlg_listbox_add(ctrl
, dlg
, colours
[i
]);
839 dlg_update_done(ctrl
, dlg
);
843 } else if (event
== EVENT_SELCHANGE
) {
844 if (ctrl
== cd
->listbox
) {
845 /* The user has selected a colour. Update the RGB text. */
846 int i
= dlg_listbox_index(ctrl
, dlg
);
851 r
= conf_get_int_int(conf
, CONF_colours
, i
*3+0);
852 g
= conf_get_int_int(conf
, CONF_colours
, i
*3+0);
853 b
= conf_get_int_int(conf
, CONF_colours
, i
*3+0);
857 } else if (event
== EVENT_VALCHANGE
) {
858 if (ctrl
== cd
->redit
|| ctrl
== cd
->gedit
|| ctrl
== cd
->bedit
) {
859 /* The user has changed the colour using the edit boxes. */
863 str
= dlg_editbox_get(ctrl
, dlg
);
866 if (cval
> 255) cval
= 255;
867 if (cval
< 0) cval
= 0;
869 i
= dlg_listbox_index(cd
->listbox
, dlg
);
871 if (ctrl
== cd
->redit
)
872 conf_set_int_int(conf
, CONF_colours
, i
*3+0, cval
);
873 else if (ctrl
== cd
->gedit
)
874 conf_set_int_int(conf
, CONF_colours
, i
*3+1, cval
);
875 else if (ctrl
== cd
->bedit
)
876 conf_set_int_int(conf
, CONF_colours
, i
*3+2, cval
);
879 } else if (event
== EVENT_ACTION
) {
880 if (ctrl
== cd
->button
) {
881 int i
= dlg_listbox_index(cd
->listbox
, dlg
);
887 * Start a colour selector, which will send us an
888 * EVENT_CALLBACK when it's finished and allow us to
889 * pick up the results.
891 dlg_coloursel_start(ctrl
, dlg
,
892 conf_get_int_int(conf
, CONF_colours
, i
*3+0),
893 conf_get_int_int(conf
, CONF_colours
, i
*3+1),
894 conf_get_int_int(conf
, CONF_colours
, i
*3+2));
896 } else if (event
== EVENT_CALLBACK
) {
897 if (ctrl
== cd
->button
) {
898 int i
= dlg_listbox_index(cd
->listbox
, dlg
);
900 * Collect the results of the colour selector. Will
901 * return nonzero on success, or zero if the colour
902 * selector did nothing (user hit Cancel, for example).
904 if (dlg_coloursel_results(ctrl
, dlg
, &r
, &g
, &b
)) {
905 conf_set_int_int(conf
, CONF_colours
, i
*3+0, r
);
906 conf_set_int_int(conf
, CONF_colours
, i
*3+0, g
);
907 conf_set_int_int(conf
, CONF_colours
, i
*3+0, b
);
916 dlg_editbox_set(cd
->redit
, dlg
, "");
917 dlg_editbox_set(cd
->gedit
, dlg
, "");
918 dlg_editbox_set(cd
->bedit
, dlg
, "");
921 sprintf(buf
, "%d", r
); dlg_editbox_set(cd
->redit
, dlg
, buf
);
922 sprintf(buf
, "%d", g
); dlg_editbox_set(cd
->gedit
, dlg
, buf
);
923 sprintf(buf
, "%d", b
); dlg_editbox_set(cd
->bedit
, dlg
, buf
);
928 struct ttymodes_data
{
929 union control
*modelist
, *valradio
, *valbox
;
930 union control
*addbutton
, *rembutton
, *listbox
;
933 static void ttymodes_handler(union control
*ctrl
, void *dlg
,
934 void *data
, int event
)
936 Conf
*conf
= (Conf
*)data
;
937 struct ttymodes_data
*td
=
938 (struct ttymodes_data
*)ctrl
->generic
.context
.p
;
940 if (event
== EVENT_REFRESH
) {
941 if (ctrl
== td
->listbox
) {
943 dlg_update_start(ctrl
, dlg
);
944 dlg_listbox_clear(ctrl
, dlg
);
945 for (val
= conf_get_str_strs(conf
, CONF_ttymodes
, NULL
, &key
);
947 val
= conf_get_str_strs(conf
, CONF_ttymodes
, key
, &key
)) {
948 char *disp
= dupprintf("%s\t%s", key
,
949 (val
[0] == 'A') ?
"(auto)" : val
+1);
950 dlg_listbox_add(ctrl
, dlg
, disp
);
953 dlg_update_done(ctrl
, dlg
);
954 } else if (ctrl
== td
->modelist
) {
956 dlg_update_start(ctrl
, dlg
);
957 dlg_listbox_clear(ctrl
, dlg
);
958 for (i
= 0; ttymodes
[i
]; i
++)
959 dlg_listbox_add(ctrl
, dlg
, ttymodes
[i
]);
960 dlg_listbox_select(ctrl
, dlg
, 0); /* *shrug* */
961 dlg_update_done(ctrl
, dlg
);
962 } else if (ctrl
== td
->valradio
) {
963 dlg_radiobutton_set(ctrl
, dlg
, 0);
965 } else if (event
== EVENT_ACTION
) {
966 if (ctrl
== td
->addbutton
) {
967 int ind
= dlg_listbox_index(td
->modelist
, dlg
);
969 char type
= dlg_radiobutton_get(td
->valradio
, dlg
) ?
'V' : 'A';
972 /* Construct new entry */
974 str
= dlg_editbox_get(td
->valbox
, dlg
);
975 val
= dupprintf("%c%s", type
, str
);
977 conf_set_str_str(conf
, CONF_ttymodes
, key
, val
);
979 dlg_refresh(td
->listbox
, dlg
);
982 } else if (ctrl
== td
->rembutton
) {
985 int multisel
= dlg_listbox_index(td
->listbox
, dlg
) < 0;
986 for (val
= conf_get_str_strs(conf
, CONF_ttymodes
, NULL
, &key
);
988 val
= conf_get_str_strs(conf
, CONF_ttymodes
, key
, &key
)) {
989 if (dlg_listbox_issel(td
->listbox
, dlg
, i
)) {
991 /* Populate controls with entry we're about to
992 * delete, for ease of editing.
993 * (If multiple entries were selected, don't
994 * touch the controls.) */
997 while (ttymodes
[ind
]) {
998 if (!strcmp(ttymodes
[ind
], key
))
1002 dlg_listbox_select(td
->modelist
, dlg
, ind
);
1003 dlg_radiobutton_set(td
->valradio
, dlg
,
1005 dlg_editbox_set(td
->valbox
, dlg
, val
+1);
1007 conf_del_str_str(conf
, CONF_ttymodes
, key
);
1011 dlg_refresh(td
->listbox
, dlg
);
1016 struct environ_data
{
1017 union control
*varbox
, *valbox
, *addbutton
, *rembutton
, *listbox
;
1020 static void environ_handler(union control
*ctrl
, void *dlg
,
1021 void *data
, int event
)
1023 Conf
*conf
= (Conf
*)data
;
1024 struct environ_data
*ed
=
1025 (struct environ_data
*)ctrl
->generic
.context
.p
;
1027 if (event
== EVENT_REFRESH
) {
1028 if (ctrl
== ed
->listbox
) {
1030 dlg_update_start(ctrl
, dlg
);
1031 dlg_listbox_clear(ctrl
, dlg
);
1032 for (val
= conf_get_str_strs(conf
, CONF_environmt
, NULL
, &key
);
1034 val
= conf_get_str_strs(conf
, CONF_environmt
, key
, &key
)) {
1035 char *p
= dupprintf("%s\t%s", key
, val
);
1036 dlg_listbox_add(ctrl
, dlg
, p
);
1039 dlg_update_done(ctrl
, dlg
);
1041 } else if (event
== EVENT_ACTION
) {
1042 if (ctrl
== ed
->addbutton
) {
1043 char *key
, *val
, *str
;
1044 key
= dlg_editbox_get(ed
->varbox
, dlg
);
1050 val
= dlg_editbox_get(ed
->valbox
, dlg
);
1057 conf_set_str_str(conf
, CONF_environmt
, key
, val
);
1058 str
= dupcat(key
, "\t", val
, NULL
);
1059 dlg_editbox_set(ed
->varbox
, dlg
, "");
1060 dlg_editbox_set(ed
->valbox
, dlg
, "");
1064 dlg_refresh(ed
->listbox
, dlg
);
1065 } else if (ctrl
== ed
->rembutton
) {
1066 int i
= dlg_listbox_index(ed
->listbox
, dlg
);
1072 key
= conf_get_str_nthstrkey(conf
, CONF_environmt
, i
);
1074 /* Populate controls with the entry we're about to delete
1075 * for ease of editing */
1076 val
= conf_get_str_str(conf
, CONF_environmt
, key
);
1077 dlg_editbox_set(ed
->varbox
, dlg
, key
);
1078 dlg_editbox_set(ed
->valbox
, dlg
, val
);
1080 conf_del_str_str(conf
, CONF_environmt
, key
);
1083 dlg_refresh(ed
->listbox
, dlg
);
1088 struct portfwd_data
{
1089 union control
*addbutton
, *rembutton
, *listbox
;
1090 union control
*sourcebox
, *destbox
, *direction
;
1092 union control
*addressfamily
;
1096 static void portfwd_handler(union control
*ctrl
, void *dlg
,
1097 void *data
, int event
)
1099 Conf
*conf
= (Conf
*)data
;
1100 struct portfwd_data
*pfd
=
1101 (struct portfwd_data
*)ctrl
->generic
.context
.p
;
1103 if (event
== EVENT_REFRESH
) {
1104 if (ctrl
== pfd
->listbox
) {
1106 dlg_update_start(ctrl
, dlg
);
1107 dlg_listbox_clear(ctrl
, dlg
);
1108 for (val
= conf_get_str_strs(conf
, CONF_portfwd
, NULL
, &key
);
1110 val
= conf_get_str_strs(conf
, CONF_portfwd
, key
, &key
)) {
1112 if (!strcmp(val
, "D"))
1113 p
= dupprintf("D%s\t", key
+1);
1115 p
= dupprintf("%s\t%s", key
, val
);
1116 dlg_listbox_add(ctrl
, dlg
, p
);
1119 dlg_update_done(ctrl
, dlg
);
1120 } else if (ctrl
== pfd
->direction
) {
1124 dlg_radiobutton_set(ctrl
, dlg
, 0);
1126 } else if (ctrl
== pfd
->addressfamily
) {
1127 dlg_radiobutton_set(ctrl
, dlg
, 0);
1130 } else if (event
== EVENT_ACTION
) {
1131 if (ctrl
== pfd
->addbutton
) {
1132 char *family
, *type
, *src
, *key
, *val
;
1137 whichbutton
= dlg_radiobutton_get(pfd
->addressfamily
, dlg
);
1138 if (whichbutton
== 1)
1140 else if (whichbutton
== 2)
1146 whichbutton
= dlg_radiobutton_get(pfd
->direction
, dlg
);
1147 if (whichbutton
== 0)
1149 else if (whichbutton
== 1)
1154 src
= dlg_editbox_get(pfd
->sourcebox
, dlg
);
1156 dlg_error_msg(dlg
, "You need to specify a source port number");
1161 val
= dlg_editbox_get(pfd
->destbox
, dlg
);
1162 if (!*val
|| !strchr(val
, ':')) {
1164 "You need to specify a destination address\n"
1165 "in the form \"host.name:port\"");
1172 val
= dupstr("D"); /* special case */
1175 key
= dupcat(family
, type
, src
, NULL
);
1178 if (conf_get_str_str_opt(conf
, CONF_portfwd
, key
)) {
1179 dlg_error_msg(dlg
, "Specified forwarding already exists");
1181 conf_set_str_str(conf
, CONF_portfwd
, key
, val
);
1186 dlg_refresh(pfd
->listbox
, dlg
);
1187 } else if (ctrl
== pfd
->rembutton
) {
1188 int i
= dlg_listbox_index(pfd
->listbox
, dlg
);
1192 char *key
, *val
, *p
;
1194 key
= conf_get_str_nthstrkey(conf
, CONF_portfwd
, i
);
1196 static const char *const afs
= "A46";
1197 static const char *const dirs
= "LRD";
1204 /* Populate controls with the entry we're about to delete
1205 * for ease of editing */
1208 afp
= strchr(afs
, *p
);
1210 idx
= afp ? afp
-afs
: 0;
1215 dlg_radiobutton_set(pfd
->addressfamily
, dlg
, idx
);
1220 val
= conf_get_str_str(conf
, CONF_portfwd
, key
);
1221 if (!strcmp(val
, "D")) {
1226 dlg_radiobutton_set(pfd
->direction
, dlg
,
1227 strchr(dirs
, dir
) - dirs
);
1230 dlg_editbox_set(pfd
->sourcebox
, dlg
, p
);
1231 dlg_editbox_set(pfd
->destbox
, dlg
, val
);
1233 conf_del_str_str(conf
, CONF_portfwd
, key
);
1236 dlg_refresh(pfd
->listbox
, dlg
);
1241 void setup_config_box(struct controlbox
*b
, int midsession
,
1242 int protocol
, int protcfginfo
)
1244 struct controlset
*s
;
1245 struct sessionsaver_data
*ssd
;
1246 struct charclass_data
*ccd
;
1247 struct colour_data
*cd
;
1248 struct ttymodes_data
*td
;
1249 struct environ_data
*ed
;
1250 struct portfwd_data
*pfd
;
1254 ssd
= (struct sessionsaver_data
*)
1255 ctrl_alloc(b
, sizeof(struct sessionsaver_data
));
1256 memset(ssd
, 0, sizeof(*ssd
));
1257 ssd
->midsession
= midsession
;
1260 * The standard panel that appears at the bottom of all panels:
1261 * Open, Cancel, Apply etc.
1263 s
= ctrl_getset(b
, "", "", "");
1264 ctrl_columns(s
, 5, 20, 20, 20, 20, 20);
1265 ssd
->okbutton
= ctrl_pushbutton(s
,
1266 (midsession ?
"Apply" : "Open"),
1267 (char)(midsession ?
'a' : 'o'),
1269 sessionsaver_handler
, P(ssd
));
1270 ssd
->okbutton
->button
.isdefault
= TRUE
;
1271 ssd
->okbutton
->generic
.column
= 3;
1272 ssd
->cancelbutton
= ctrl_pushbutton(s
, "Cancel", 'c', HELPCTX(no_help
),
1273 sessionsaver_handler
, P(ssd
));
1274 ssd
->cancelbutton
->button
.iscancel
= TRUE
;
1275 ssd
->cancelbutton
->generic
.column
= 4;
1276 /* We carefully don't close the 5-column part, so that platform-
1277 * specific add-ons can put extra buttons alongside Open and Cancel. */
1280 * The Session panel.
1282 str
= dupprintf("Basic options for your %s session", appname
);
1283 ctrl_settitle(b
, "Session", str
);
1287 struct hostport
*hp
= (struct hostport
*)
1288 ctrl_alloc(b
, sizeof(struct hostport
));
1290 s
= ctrl_getset(b
, "Session", "hostport",
1291 "Specify the destination you want to connect to");
1292 ctrl_columns(s
, 2, 75, 25);
1293 c
= ctrl_editbox(s
, HOST_BOX_TITLE
, 'n', 100,
1294 HELPCTX(session_hostname
),
1295 config_host_handler
, I(0), I(0));
1296 c
->generic
.column
= 0;
1298 c
= ctrl_editbox(s
, PORT_BOX_TITLE
, 'p', 100,
1299 HELPCTX(session_hostname
),
1300 config_port_handler
, I(0), I(0));
1301 c
->generic
.column
= 1;
1303 ctrl_columns(s
, 1, 100);
1305 if (!backend_from_proto(PROT_SSH
)) {
1306 ctrl_radiobuttons(s
, "Connection type:", NO_SHORTCUT
, 3,
1307 HELPCTX(session_hostname
),
1308 config_protocolbuttons_handler
, P(hp
),
1309 "Raw", 'w', I(PROT_RAW
),
1310 "Telnet", 't', I(PROT_TELNET
),
1311 "Rlogin", 'i', I(PROT_RLOGIN
),
1314 ctrl_radiobuttons(s
, "Connection type:", NO_SHORTCUT
, 4,
1315 HELPCTX(session_hostname
),
1316 config_protocolbuttons_handler
, P(hp
),
1317 "Raw", 'w', I(PROT_RAW
),
1318 "Telnet", 't', I(PROT_TELNET
),
1319 "Rlogin", 'i', I(PROT_RLOGIN
),
1320 "SSH", 's', I(PROT_SSH
),
1326 * The Load/Save panel is available even in mid-session.
1328 s
= ctrl_getset(b
, "Session", "savedsessions",
1329 midsession ?
"Save the current session settings" :
1330 "Load, save or delete a stored session");
1331 ctrl_columns(s
, 2, 75, 25);
1332 get_sesslist(&ssd
->sesslist
, TRUE
);
1333 ssd
->editbox
= ctrl_editbox(s
, "Saved Sessions", 'e', 100,
1334 HELPCTX(session_saved
),
1335 sessionsaver_handler
, P(ssd
), P(NULL
));
1336 ssd
->editbox
->generic
.column
= 0;
1337 /* Reset columns so that the buttons are alongside the list, rather
1338 * than alongside that edit box. */
1339 ctrl_columns(s
, 1, 100);
1340 ctrl_columns(s
, 2, 75, 25);
1341 ssd
->listbox
= ctrl_listbox(s
, NULL
, NO_SHORTCUT
,
1342 HELPCTX(session_saved
),
1343 sessionsaver_handler
, P(ssd
));
1344 ssd
->listbox
->generic
.column
= 0;
1345 ssd
->listbox
->listbox
.height
= 7;
1347 ssd
->loadbutton
= ctrl_pushbutton(s
, "Load", 'l',
1348 HELPCTX(session_saved
),
1349 sessionsaver_handler
, P(ssd
));
1350 ssd
->loadbutton
->generic
.column
= 1;
1352 /* We can't offer the Load button mid-session, as it would allow the
1353 * user to load and subsequently save settings they can't see. (And
1354 * also change otherwise immutable settings underfoot; that probably
1355 * shouldn't be a problem, but.) */
1356 ssd
->loadbutton
= NULL
;
1358 /* "Save" button is permitted mid-session. */
1359 ssd
->savebutton
= ctrl_pushbutton(s
, "Save", 'v',
1360 HELPCTX(session_saved
),
1361 sessionsaver_handler
, P(ssd
));
1362 ssd
->savebutton
->generic
.column
= 1;
1364 ssd
->delbutton
= ctrl_pushbutton(s
, "Delete", 'd',
1365 HELPCTX(session_saved
),
1366 sessionsaver_handler
, P(ssd
));
1367 ssd
->delbutton
->generic
.column
= 1;
1369 /* Disable the Delete button mid-session too, for UI consistency. */
1370 ssd
->delbutton
= NULL
;
1372 ctrl_columns(s
, 1, 100);
1374 s
= ctrl_getset(b
, "Session", "otheropts", NULL
);
1375 c
= ctrl_radiobuttons(s
, "Close window on exit:", 'x', 4,
1376 HELPCTX(session_coe
),
1377 conf_radiobutton_handler
,
1378 I(CONF_close_on_exit
),
1379 "Always", I(FORCE_ON
),
1380 "Never", I(FORCE_OFF
),
1381 "Only on clean exit", I(AUTO
), NULL
);
1384 * The Session/Logging panel.
1386 ctrl_settitle(b
, "Session/Logging", "Options controlling session logging");
1388 s
= ctrl_getset(b
, "Session/Logging", "main", NULL
);
1390 * The logging buttons change depending on whether SSH packet
1391 * logging can sensibly be available.
1394 char *sshlogname
, *sshrawlogname
;
1395 if ((midsession
&& protocol
== PROT_SSH
) ||
1396 (!midsession
&& backend_from_proto(PROT_SSH
))) {
1397 sshlogname
= "SSH packets";
1398 sshrawlogname
= "SSH packets and raw data";
1400 sshlogname
= NULL
; /* this will disable both buttons */
1401 sshrawlogname
= NULL
; /* this will just placate optimisers */
1403 ctrl_radiobuttons(s
, "Session logging:", NO_SHORTCUT
, 2,
1404 HELPCTX(logging_main
),
1405 loggingbuttons_handler
,
1407 "None", 't', I(LGTYP_NONE
),
1408 "Printable output", 'p', I(LGTYP_ASCII
),
1409 "All session output", 'l', I(LGTYP_DEBUG
),
1410 sshlogname
, 's', I(LGTYP_PACKETS
),
1411 sshrawlogname
, 'r', I(LGTYP_SSHRAW
),
1414 ctrl_filesel(s
, "Log file name:", 'f',
1415 NULL
, TRUE
, "Select session log file name",
1416 HELPCTX(logging_filename
),
1417 conf_filesel_handler
, I(CONF_logfilename
));
1418 ctrl_text(s
, "(Log file name can contain &Y, &M, &D for date,"
1419 " &T for time, and &H for host name)",
1420 HELPCTX(logging_filename
));
1421 ctrl_radiobuttons(s
, "What to do if the log file already exists:", 'e', 1,
1422 HELPCTX(logging_exists
),
1423 conf_radiobutton_handler
, I(CONF_logxfovr
),
1424 "Always overwrite it", I(LGXF_OVR
),
1425 "Always append to the end of it", I(LGXF_APN
),
1426 "Ask the user every time", I(LGXF_ASK
), NULL
);
1427 ctrl_checkbox(s
, "Flush log file frequently", 'u',
1428 HELPCTX(logging_flush
),
1429 conf_checkbox_handler
, I(CONF_logflush
));
1431 if ((midsession
&& protocol
== PROT_SSH
) ||
1432 (!midsession
&& backend_from_proto(PROT_SSH
))) {
1433 s
= ctrl_getset(b
, "Session/Logging", "ssh",
1434 "Options specific to SSH packet logging");
1435 ctrl_checkbox(s
, "Omit known password fields", 'k',
1436 HELPCTX(logging_ssh_omit_password
),
1437 conf_checkbox_handler
, I(CONF_logomitpass
));
1438 ctrl_checkbox(s
, "Omit session data", 'd',
1439 HELPCTX(logging_ssh_omit_data
),
1440 conf_checkbox_handler
, I(CONF_logomitdata
));
1444 * The Terminal panel.
1446 ctrl_settitle(b
, "Terminal", "Options controlling the terminal emulation");
1448 s
= ctrl_getset(b
, "Terminal", "general", "Set various terminal options");
1449 ctrl_checkbox(s
, "Auto wrap mode initially on", 'w',
1450 HELPCTX(terminal_autowrap
),
1451 conf_checkbox_handler
, I(CONF_wrap_mode
));
1452 ctrl_checkbox(s
, "DEC Origin Mode initially on", 'd',
1453 HELPCTX(terminal_decom
),
1454 conf_checkbox_handler
, I(CONF_dec_om
));
1455 ctrl_checkbox(s
, "Implicit CR in every LF", 'r',
1456 HELPCTX(terminal_lfhascr
),
1457 conf_checkbox_handler
, I(CONF_lfhascr
));
1458 ctrl_checkbox(s
, "Implicit LF in every CR", 'f',
1459 HELPCTX(terminal_crhaslf
),
1460 conf_checkbox_handler
, I(CONF_crhaslf
));
1461 ctrl_checkbox(s
, "Use background colour to erase screen", 'e',
1462 HELPCTX(terminal_bce
),
1463 conf_checkbox_handler
, I(CONF_bce
));
1464 ctrl_checkbox(s
, "Enable blinking text", 'n',
1465 HELPCTX(terminal_blink
),
1466 conf_checkbox_handler
, I(CONF_blinktext
));
1467 ctrl_editbox(s
, "Answerback to ^E:", 's', 100,
1468 HELPCTX(terminal_answerback
),
1469 conf_editbox_handler
, I(CONF_answerback
), I(1));
1471 s
= ctrl_getset(b
, "Terminal", "ldisc", "Line discipline options");
1472 ctrl_radiobuttons(s
, "Local echo:", 'l', 3,
1473 HELPCTX(terminal_localecho
),
1474 conf_radiobutton_handler
,I(CONF_localecho
),
1476 "Force on", I(FORCE_ON
),
1477 "Force off", I(FORCE_OFF
), NULL
);
1478 ctrl_radiobuttons(s
, "Local line editing:", 't', 3,
1479 HELPCTX(terminal_localedit
),
1480 conf_radiobutton_handler
,I(CONF_localedit
),
1482 "Force on", I(FORCE_ON
),
1483 "Force off", I(FORCE_OFF
), NULL
);
1485 s
= ctrl_getset(b
, "Terminal", "printing", "Remote-controlled printing");
1486 ctrl_combobox(s
, "Printer to send ANSI printer output to:", 'p', 100,
1487 HELPCTX(terminal_printing
),
1488 printerbox_handler
, P(NULL
), P(NULL
));
1491 * The Terminal/Keyboard panel.
1493 ctrl_settitle(b
, "Terminal/Keyboard",
1494 "Options controlling the effects of keys");
1496 s
= ctrl_getset(b
, "Terminal/Keyboard", "mappings",
1497 "Change the sequences sent by:");
1498 ctrl_radiobuttons(s
, "The Backspace key", 'b', 2,
1499 HELPCTX(keyboard_backspace
),
1500 conf_radiobutton_handler
,
1501 I(CONF_bksp_is_delete
),
1502 "Control-H", I(0), "Control-? (127)", I(1), NULL
);
1503 ctrl_radiobuttons(s
, "The Home and End keys", 'e', 2,
1504 HELPCTX(keyboard_homeend
),
1505 conf_radiobutton_handler
,
1506 I(CONF_rxvt_homeend
),
1507 "Standard", I(0), "rxvt", I(1), NULL
);
1508 ctrl_radiobuttons(s
, "The Function keys and keypad", 'f', 3,
1509 HELPCTX(keyboard_funkeys
),
1510 conf_radiobutton_handler
,
1512 "ESC[n~", I(0), "Linux", I(1), "Xterm R6", I(2),
1513 "VT400", I(3), "VT100+", I(4), "SCO", I(5), NULL
);
1515 s
= ctrl_getset(b
, "Terminal/Keyboard", "appkeypad",
1516 "Application keypad settings:");
1517 ctrl_radiobuttons(s
, "Initial state of cursor keys:", 'r', 3,
1518 HELPCTX(keyboard_appcursor
),
1519 conf_radiobutton_handler
,
1521 "Normal", I(0), "Application", I(1), NULL
);
1522 ctrl_radiobuttons(s
, "Initial state of numeric keypad:", 'n', 3,
1523 HELPCTX(keyboard_appkeypad
),
1524 numeric_keypad_handler
, P(NULL
),
1525 "Normal", I(0), "Application", I(1), "NetHack", I(2),
1529 * The Terminal/Bell panel.
1531 ctrl_settitle(b
, "Terminal/Bell",
1532 "Options controlling the terminal bell");
1534 s
= ctrl_getset(b
, "Terminal/Bell", "style", "Set the style of bell");
1535 ctrl_radiobuttons(s
, "Action to happen when a bell occurs:", 'b', 1,
1536 HELPCTX(bell_style
),
1537 conf_radiobutton_handler
, I(CONF_beep
),
1538 "None (bell disabled)", I(BELL_DISABLED
),
1539 "Make default system alert sound", I(BELL_DEFAULT
),
1540 "Visual bell (flash window)", I(BELL_VISUAL
), NULL
);
1542 s
= ctrl_getset(b
, "Terminal/Bell", "overload",
1543 "Control the bell overload behaviour");
1544 ctrl_checkbox(s
, "Bell is temporarily disabled when over-used", 'd',
1545 HELPCTX(bell_overload
),
1546 conf_checkbox_handler
, I(CONF_bellovl
));
1547 ctrl_editbox(s
, "Over-use means this many bells...", 'm', 20,
1548 HELPCTX(bell_overload
),
1549 conf_editbox_handler
, I(CONF_bellovl_n
), I(-1));
1550 ctrl_editbox(s
, "... in this many seconds", 't', 20,
1551 HELPCTX(bell_overload
),
1552 conf_editbox_handler
, I(CONF_bellovl_t
),
1554 ctrl_text(s
, "The bell is re-enabled after a few seconds of silence.",
1555 HELPCTX(bell_overload
));
1556 ctrl_editbox(s
, "Seconds of silence required", 's', 20,
1557 HELPCTX(bell_overload
),
1558 conf_editbox_handler
, I(CONF_bellovl_s
),
1562 * The Terminal/Features panel.
1564 ctrl_settitle(b
, "Terminal/Features",
1565 "Enabling and disabling advanced terminal features");
1567 s
= ctrl_getset(b
, "Terminal/Features", "main", NULL
);
1568 ctrl_checkbox(s
, "Disable application cursor keys mode", 'u',
1569 HELPCTX(features_application
),
1570 conf_checkbox_handler
, I(CONF_no_applic_c
));
1571 ctrl_checkbox(s
, "Disable application keypad mode", 'k',
1572 HELPCTX(features_application
),
1573 conf_checkbox_handler
, I(CONF_no_applic_k
));
1574 ctrl_checkbox(s
, "Disable xterm-style mouse reporting", 'x',
1575 HELPCTX(features_mouse
),
1576 conf_checkbox_handler
, I(CONF_no_mouse_rep
));
1577 ctrl_checkbox(s
, "Disable remote-controlled terminal resizing", 's',
1578 HELPCTX(features_resize
),
1579 conf_checkbox_handler
,
1580 I(CONF_no_remote_resize
));
1581 ctrl_checkbox(s
, "Disable switching to alternate terminal screen", 'w',
1582 HELPCTX(features_altscreen
),
1583 conf_checkbox_handler
, I(CONF_no_alt_screen
));
1584 ctrl_checkbox(s
, "Disable remote-controlled window title changing", 't',
1585 HELPCTX(features_retitle
),
1586 conf_checkbox_handler
,
1587 I(CONF_no_remote_wintitle
));
1588 ctrl_radiobuttons(s
, "Response to remote title query (SECURITY):", 'q', 3,
1589 HELPCTX(features_qtitle
),
1590 conf_radiobutton_handler
,
1591 I(CONF_remote_qtitle_action
),
1592 "None", I(TITLE_NONE
),
1593 "Empty string", I(TITLE_EMPTY
),
1594 "Window title", I(TITLE_REAL
), NULL
);
1595 ctrl_checkbox(s
, "Disable destructive backspace on server sending ^?",'b',
1596 HELPCTX(features_dbackspace
),
1597 conf_checkbox_handler
, I(CONF_no_dbackspace
));
1598 ctrl_checkbox(s
, "Disable remote-controlled character set configuration",
1599 'r', HELPCTX(features_charset
), conf_checkbox_handler
,
1600 I(CONF_no_remote_charset
));
1601 ctrl_checkbox(s
, "Disable Arabic text shaping",
1602 'l', HELPCTX(features_arabicshaping
), conf_checkbox_handler
,
1603 I(CONF_arabicshaping
));
1604 ctrl_checkbox(s
, "Disable bidirectional text display",
1605 'd', HELPCTX(features_bidi
), conf_checkbox_handler
,
1611 str
= dupprintf("Options controlling %s's window", appname
);
1612 ctrl_settitle(b
, "Window", str
);
1615 s
= ctrl_getset(b
, "Window", "size", "Set the size of the window");
1616 ctrl_columns(s
, 2, 50, 50);
1617 c
= ctrl_editbox(s
, "Columns", 'm', 100,
1618 HELPCTX(window_size
),
1619 conf_editbox_handler
, I(CONF_width
), I(-1));
1620 c
->generic
.column
= 0;
1621 c
= ctrl_editbox(s
, "Rows", 'r', 100,
1622 HELPCTX(window_size
),
1623 conf_editbox_handler
, I(CONF_height
),I(-1));
1624 c
->generic
.column
= 1;
1625 ctrl_columns(s
, 1, 100);
1627 s
= ctrl_getset(b
, "Window", "scrollback",
1628 "Control the scrollback in the window");
1629 ctrl_editbox(s
, "Lines of scrollback", 's', 50,
1630 HELPCTX(window_scrollback
),
1631 conf_editbox_handler
, I(CONF_savelines
), I(-1));
1632 ctrl_checkbox(s
, "Display scrollbar", 'd',
1633 HELPCTX(window_scrollback
),
1634 conf_checkbox_handler
, I(CONF_scrollbar
));
1635 ctrl_checkbox(s
, "Reset scrollback on keypress", 'k',
1636 HELPCTX(window_scrollback
),
1637 conf_checkbox_handler
, I(CONF_scroll_on_key
));
1638 ctrl_checkbox(s
, "Reset scrollback on display activity", 'p',
1639 HELPCTX(window_scrollback
),
1640 conf_checkbox_handler
, I(CONF_scroll_on_disp
));
1641 ctrl_checkbox(s
, "Push erased text into scrollback", 'e',
1642 HELPCTX(window_erased
),
1643 conf_checkbox_handler
,
1644 I(CONF_erase_to_scrollback
));
1647 * The Window/Appearance panel.
1649 str
= dupprintf("Configure the appearance of %s's window", appname
);
1650 ctrl_settitle(b
, "Window/Appearance", str
);
1653 s
= ctrl_getset(b
, "Window/Appearance", "cursor",
1654 "Adjust the use of the cursor");
1655 ctrl_radiobuttons(s
, "Cursor appearance:", NO_SHORTCUT
, 3,
1656 HELPCTX(appearance_cursor
),
1657 conf_radiobutton_handler
,
1658 I(CONF_cursor_type
),
1660 "Underline", 'u', I(1),
1661 "Vertical line", 'v', I(2), NULL
);
1662 ctrl_checkbox(s
, "Cursor blinks", 'b',
1663 HELPCTX(appearance_cursor
),
1664 conf_checkbox_handler
, I(CONF_blink_cur
));
1666 s
= ctrl_getset(b
, "Window/Appearance", "font",
1668 ctrl_fontsel(s
, "Font used in the terminal window", 'n',
1669 HELPCTX(appearance_font
),
1670 conf_fontsel_handler
, I(CONF_font
));
1672 s
= ctrl_getset(b
, "Window/Appearance", "mouse",
1673 "Adjust the use of the mouse pointer");
1674 ctrl_checkbox(s
, "Hide mouse pointer when typing in window", 'p',
1675 HELPCTX(appearance_hidemouse
),
1676 conf_checkbox_handler
, I(CONF_hide_mouseptr
));
1678 s
= ctrl_getset(b
, "Window/Appearance", "border",
1679 "Adjust the window border");
1680 ctrl_editbox(s
, "Gap between text and window edge:", 'e', 20,
1681 HELPCTX(appearance_border
),
1682 conf_editbox_handler
,
1683 I(CONF_window_border
), I(-1));
1686 * The Window/Behaviour panel.
1688 str
= dupprintf("Configure the behaviour of %s's window", appname
);
1689 ctrl_settitle(b
, "Window/Behaviour", str
);
1692 s
= ctrl_getset(b
, "Window/Behaviour", "title",
1693 "Adjust the behaviour of the window title");
1694 ctrl_editbox(s
, "Window title:", 't', 100,
1695 HELPCTX(appearance_title
),
1696 conf_editbox_handler
, I(CONF_wintitle
), I(1));
1697 ctrl_checkbox(s
, "Separate window and icon titles", 'i',
1698 HELPCTX(appearance_title
),
1699 conf_checkbox_handler
,
1700 I(CHECKBOX_INVERT
| CONF_win_name_always
));
1702 s
= ctrl_getset(b
, "Window/Behaviour", "main", NULL
);
1703 ctrl_checkbox(s
, "Warn before closing window", 'w',
1704 HELPCTX(behaviour_closewarn
),
1705 conf_checkbox_handler
, I(CONF_warn_on_close
));
1708 * The Window/Translation panel.
1710 ctrl_settitle(b
, "Window/Translation",
1711 "Options controlling character set translation");
1713 s
= ctrl_getset(b
, "Window/Translation", "trans",
1714 "Character set translation");
1715 ctrl_combobox(s
, "Remote character set:",
1716 'r', 100, HELPCTX(translation_codepage
),
1717 codepage_handler
, P(NULL
), P(NULL
));
1719 s
= ctrl_getset(b
, "Window/Translation", "tweaks", NULL
);
1720 ctrl_checkbox(s
, "Treat CJK ambiguous characters as wide", 'w',
1721 HELPCTX(translation_cjk_ambig_wide
),
1722 conf_checkbox_handler
, I(CONF_cjk_ambig_wide
));
1724 str
= dupprintf("Adjust how %s handles line drawing characters", appname
);
1725 s
= ctrl_getset(b
, "Window/Translation", "linedraw", str
);
1727 ctrl_radiobuttons(s
, "Handling of line drawing characters:", NO_SHORTCUT
,1,
1728 HELPCTX(translation_linedraw
),
1729 conf_radiobutton_handler
,
1731 "Use Unicode line drawing code points",'u',I(VT_UNICODE
),
1732 "Poor man's line drawing (+, - and |)",'p',I(VT_POORMAN
),
1734 ctrl_checkbox(s
, "Copy and paste line drawing characters as lqqqk",'d',
1735 HELPCTX(selection_linedraw
),
1736 conf_checkbox_handler
, I(CONF_rawcnp
));
1739 * The Window/Selection panel.
1741 ctrl_settitle(b
, "Window/Selection", "Options controlling copy and paste");
1743 s
= ctrl_getset(b
, "Window/Selection", "mouse",
1744 "Control use of mouse");
1745 ctrl_checkbox(s
, "Shift overrides application's use of mouse", 'p',
1746 HELPCTX(selection_shiftdrag
),
1747 conf_checkbox_handler
, I(CONF_mouse_override
));
1748 ctrl_radiobuttons(s
,
1749 "Default selection mode (Alt+drag does the other one):",
1751 HELPCTX(selection_rect
),
1752 conf_radiobutton_handler
,
1753 I(CONF_rect_select
),
1754 "Normal", 'n', I(0),
1755 "Rectangular block", 'r', I(1), NULL
);
1757 s
= ctrl_getset(b
, "Window/Selection", "charclass",
1758 "Control the select-one-word-at-a-time mode");
1759 ccd
= (struct charclass_data
*)
1760 ctrl_alloc(b
, sizeof(struct charclass_data
));
1761 ccd
->listbox
= ctrl_listbox(s
, "Character classes:", 'e',
1762 HELPCTX(selection_charclasses
),
1763 charclass_handler
, P(ccd
));
1764 ccd
->listbox
->listbox
.multisel
= 1;
1765 ccd
->listbox
->listbox
.ncols
= 4;
1766 ccd
->listbox
->listbox
.percentages
= snewn(4, int);
1767 ccd
->listbox
->listbox
.percentages
[0] = 15;
1768 ccd
->listbox
->listbox
.percentages
[1] = 25;
1769 ccd
->listbox
->listbox
.percentages
[2] = 20;
1770 ccd
->listbox
->listbox
.percentages
[3] = 40;
1771 ctrl_columns(s
, 2, 67, 33);
1772 ccd
->editbox
= ctrl_editbox(s
, "Set to class", 't', 50,
1773 HELPCTX(selection_charclasses
),
1774 charclass_handler
, P(ccd
), P(NULL
));
1775 ccd
->editbox
->generic
.column
= 0;
1776 ccd
->button
= ctrl_pushbutton(s
, "Set", 's',
1777 HELPCTX(selection_charclasses
),
1778 charclass_handler
, P(ccd
));
1779 ccd
->button
->generic
.column
= 1;
1780 ctrl_columns(s
, 1, 100);
1783 * The Window/Colours panel.
1785 ctrl_settitle(b
, "Window/Colours", "Options controlling use of colours");
1787 s
= ctrl_getset(b
, "Window/Colours", "general",
1788 "General options for colour usage");
1789 ctrl_checkbox(s
, "Allow terminal to specify ANSI colours", 'i',
1790 HELPCTX(colours_ansi
),
1791 conf_checkbox_handler
, I(CONF_ansi_colour
));
1792 ctrl_checkbox(s
, "Allow terminal to use xterm 256-colour mode", '2',
1793 HELPCTX(colours_xterm256
), conf_checkbox_handler
,
1794 I(CONF_xterm_256_colour
));
1795 ctrl_checkbox(s
, "Bolded text is a different colour", 'b',
1796 HELPCTX(colours_bold
),
1797 conf_checkbox_handler
, I(CONF_bold_colour
));
1799 str
= dupprintf("Adjust the precise colours %s displays", appname
);
1800 s
= ctrl_getset(b
, "Window/Colours", "adjust", str
);
1802 ctrl_text(s
, "Select a colour from the list, and then click the"
1803 " Modify button to change its appearance.",
1804 HELPCTX(colours_config
));
1805 ctrl_columns(s
, 2, 67, 33);
1806 cd
= (struct colour_data
*)ctrl_alloc(b
, sizeof(struct colour_data
));
1807 cd
->listbox
= ctrl_listbox(s
, "Select a colour to adjust:", 'u',
1808 HELPCTX(colours_config
), colour_handler
, P(cd
));
1809 cd
->listbox
->generic
.column
= 0;
1810 cd
->listbox
->listbox
.height
= 7;
1811 c
= ctrl_text(s
, "RGB value:", HELPCTX(colours_config
));
1812 c
->generic
.column
= 1;
1813 cd
->redit
= ctrl_editbox(s
, "Red", 'r', 50, HELPCTX(colours_config
),
1814 colour_handler
, P(cd
), P(NULL
));
1815 cd
->redit
->generic
.column
= 1;
1816 cd
->gedit
= ctrl_editbox(s
, "Green", 'n', 50, HELPCTX(colours_config
),
1817 colour_handler
, P(cd
), P(NULL
));
1818 cd
->gedit
->generic
.column
= 1;
1819 cd
->bedit
= ctrl_editbox(s
, "Blue", 'e', 50, HELPCTX(colours_config
),
1820 colour_handler
, P(cd
), P(NULL
));
1821 cd
->bedit
->generic
.column
= 1;
1822 cd
->button
= ctrl_pushbutton(s
, "Modify", 'm', HELPCTX(colours_config
),
1823 colour_handler
, P(cd
));
1824 cd
->button
->generic
.column
= 1;
1825 ctrl_columns(s
, 1, 100);
1828 * The Connection panel. This doesn't show up if we're in a
1829 * non-network utility such as pterm. We tell this by being
1830 * passed a protocol < 0.
1832 if (protocol
>= 0) {
1833 ctrl_settitle(b
, "Connection", "Options controlling the connection");
1835 s
= ctrl_getset(b
, "Connection", "keepalive",
1836 "Sending of null packets to keep session active");
1837 ctrl_editbox(s
, "Seconds between keepalives (0 to turn off)", 'k', 20,
1838 HELPCTX(connection_keepalive
),
1839 conf_editbox_handler
, I(CONF_ping_interval
),
1843 s
= ctrl_getset(b
, "Connection", "tcp",
1844 "Low-level TCP connection options");
1845 ctrl_checkbox(s
, "Disable Nagle's algorithm (TCP_NODELAY option)",
1846 'n', HELPCTX(connection_nodelay
),
1847 conf_checkbox_handler
,
1848 I(CONF_tcp_nodelay
));
1849 ctrl_checkbox(s
, "Enable TCP keepalives (SO_KEEPALIVE option)",
1850 'p', HELPCTX(connection_tcpkeepalive
),
1851 conf_checkbox_handler
,
1852 I(CONF_tcp_keepalives
));
1854 s
= ctrl_getset(b
, "Connection", "ipversion",
1855 "Internet protocol version");
1856 ctrl_radiobuttons(s
, NULL
, NO_SHORTCUT
, 3,
1857 HELPCTX(connection_ipversion
),
1858 conf_radiobutton_handler
,
1859 I(CONF_addressfamily
),
1860 "Auto", 'u', I(ADDRTYPE_UNSPEC
),
1861 "IPv4", '4', I(ADDRTYPE_IPV4
),
1862 "IPv6", '6', I(ADDRTYPE_IPV6
),
1867 char *label
= backend_from_proto(PROT_SSH
) ?
1868 "Logical name of remote host (e.g. for SSH key lookup):" :
1869 "Logical name of remote host:";
1870 s
= ctrl_getset(b
, "Connection", "identity",
1871 "Logical name of remote host");
1872 ctrl_editbox(s
, label
, 'm', 100,
1873 HELPCTX(connection_loghost
),
1874 conf_editbox_handler
, I(CONF_loghost
), I(1));
1879 * A sub-panel Connection/Data, containing options that
1880 * decide on data to send to the server.
1883 ctrl_settitle(b
, "Connection/Data", "Data to send to the server");
1885 s
= ctrl_getset(b
, "Connection/Data", "login",
1887 ctrl_editbox(s
, "Auto-login username", 'u', 50,
1888 HELPCTX(connection_username
),
1889 conf_editbox_handler
, I(CONF_username
), I(1));
1891 /* We assume the local username is sufficiently stable
1892 * to include on the dialog box. */
1893 char *user
= get_username();
1894 char *userlabel
= dupprintf("Use system username (%s)",
1897 ctrl_radiobuttons(s
, "When username is not specified:", 'n', 4,
1898 HELPCTX(connection_username_from_env
),
1899 conf_radiobutton_handler
,
1900 I(CONF_username_from_env
),
1907 s
= ctrl_getset(b
, "Connection/Data", "term",
1908 "Terminal details");
1909 ctrl_editbox(s
, "Terminal-type string", 't', 50,
1910 HELPCTX(connection_termtype
),
1911 conf_editbox_handler
, I(CONF_termtype
), I(1));
1912 ctrl_editbox(s
, "Terminal speeds", 's', 50,
1913 HELPCTX(connection_termspeed
),
1914 conf_editbox_handler
, I(CONF_termspeed
), I(1));
1916 s
= ctrl_getset(b
, "Connection/Data", "env",
1917 "Environment variables");
1918 ctrl_columns(s
, 2, 80, 20);
1919 ed
= (struct environ_data
*)
1920 ctrl_alloc(b
, sizeof(struct environ_data
));
1921 ed
->varbox
= ctrl_editbox(s
, "Variable", 'v', 60,
1922 HELPCTX(telnet_environ
),
1923 environ_handler
, P(ed
), P(NULL
));
1924 ed
->varbox
->generic
.column
= 0;
1925 ed
->valbox
= ctrl_editbox(s
, "Value", 'l', 60,
1926 HELPCTX(telnet_environ
),
1927 environ_handler
, P(ed
), P(NULL
));
1928 ed
->valbox
->generic
.column
= 0;
1929 ed
->addbutton
= ctrl_pushbutton(s
, "Add", 'd',
1930 HELPCTX(telnet_environ
),
1931 environ_handler
, P(ed
));
1932 ed
->addbutton
->generic
.column
= 1;
1933 ed
->rembutton
= ctrl_pushbutton(s
, "Remove", 'r',
1934 HELPCTX(telnet_environ
),
1935 environ_handler
, P(ed
));
1936 ed
->rembutton
->generic
.column
= 1;
1937 ctrl_columns(s
, 1, 100);
1938 ed
->listbox
= ctrl_listbox(s
, NULL
, NO_SHORTCUT
,
1939 HELPCTX(telnet_environ
),
1940 environ_handler
, P(ed
));
1941 ed
->listbox
->listbox
.height
= 3;
1942 ed
->listbox
->listbox
.ncols
= 2;
1943 ed
->listbox
->listbox
.percentages
= snewn(2, int);
1944 ed
->listbox
->listbox
.percentages
[0] = 30;
1945 ed
->listbox
->listbox
.percentages
[1] = 70;
1952 * The Connection/Proxy panel.
1954 ctrl_settitle(b
, "Connection/Proxy",
1955 "Options controlling proxy usage");
1957 s
= ctrl_getset(b
, "Connection/Proxy", "basics", NULL
);
1958 ctrl_radiobuttons(s
, "Proxy type:", 't', 3,
1959 HELPCTX(proxy_type
),
1960 conf_radiobutton_handler
,
1962 "None", I(PROXY_NONE
),
1963 "SOCKS 4", I(PROXY_SOCKS4
),
1964 "SOCKS 5", I(PROXY_SOCKS5
),
1965 "HTTP", I(PROXY_HTTP
),
1966 "Telnet", I(PROXY_TELNET
),
1968 ctrl_columns(s
, 2, 80, 20);
1969 c
= ctrl_editbox(s
, "Proxy hostname", 'y', 100,
1970 HELPCTX(proxy_main
),
1971 conf_editbox_handler
,
1972 I(CONF_proxy_host
), I(1));
1973 c
->generic
.column
= 0;
1974 c
= ctrl_editbox(s
, "Port", 'p', 100,
1975 HELPCTX(proxy_main
),
1976 conf_editbox_handler
,
1979 c
->generic
.column
= 1;
1980 ctrl_columns(s
, 1, 100);
1981 ctrl_editbox(s
, "Exclude Hosts/IPs", 'e', 100,
1982 HELPCTX(proxy_exclude
),
1983 conf_editbox_handler
,
1984 I(CONF_proxy_exclude_list
), I(1));
1985 ctrl_checkbox(s
, "Consider proxying local host connections", 'x',
1986 HELPCTX(proxy_exclude
),
1987 conf_checkbox_handler
,
1988 I(CONF_even_proxy_localhost
));
1989 ctrl_radiobuttons(s
, "Do DNS name lookup at proxy end:", 'd', 3,
1991 conf_radiobutton_handler
,
1995 "Yes", I(FORCE_ON
), NULL
);
1996 ctrl_editbox(s
, "Username", 'u', 60,
1997 HELPCTX(proxy_auth
),
1998 conf_editbox_handler
,
1999 I(CONF_proxy_username
), I(1));
2000 c
= ctrl_editbox(s
, "Password", 'w', 60,
2001 HELPCTX(proxy_auth
),
2002 conf_editbox_handler
,
2003 I(CONF_proxy_password
), I(1));
2004 c
->editbox
.password
= 1;
2005 ctrl_editbox(s
, "Telnet command", 'm', 100,
2006 HELPCTX(proxy_command
),
2007 conf_editbox_handler
,
2008 I(CONF_proxy_telnet_command
), I(1));
2012 * The Telnet panel exists in the base config box, and in a
2013 * mid-session reconfig box _if_ we're using Telnet.
2015 if (!midsession
|| protocol
== PROT_TELNET
) {
2017 * The Connection/Telnet panel.
2019 ctrl_settitle(b
, "Connection/Telnet",
2020 "Options controlling Telnet connections");
2022 s
= ctrl_getset(b
, "Connection/Telnet", "protocol",
2023 "Telnet protocol adjustments");
2026 ctrl_radiobuttons(s
, "Handling of OLD_ENVIRON ambiguity:",
2028 HELPCTX(telnet_oldenviron
),
2029 conf_radiobutton_handler
,
2030 I(CONF_rfc_environ
),
2031 "BSD (commonplace)", 'b', I(0),
2032 "RFC 1408 (unusual)", 'f', I(1), NULL
);
2033 ctrl_radiobuttons(s
, "Telnet negotiation mode:", 't', 2,
2034 HELPCTX(telnet_passive
),
2035 conf_radiobutton_handler
,
2036 I(CONF_passive_telnet
),
2037 "Passive", I(1), "Active", I(0), NULL
);
2039 ctrl_checkbox(s
, "Keyboard sends Telnet special commands", 'k',
2040 HELPCTX(telnet_specialkeys
),
2041 conf_checkbox_handler
,
2042 I(CONF_telnet_keyboard
));
2043 ctrl_checkbox(s
, "Return key sends Telnet New Line instead of ^M",
2044 'm', HELPCTX(telnet_newline
),
2045 conf_checkbox_handler
,
2046 I(CONF_telnet_newline
));
2052 * The Connection/Rlogin panel.
2054 ctrl_settitle(b
, "Connection/Rlogin",
2055 "Options controlling Rlogin connections");
2057 s
= ctrl_getset(b
, "Connection/Rlogin", "data",
2058 "Data to send to the server");
2059 ctrl_editbox(s
, "Local username:", 'l', 50,
2060 HELPCTX(rlogin_localuser
),
2061 conf_editbox_handler
, I(CONF_localusername
), I(1));
2066 * All the SSH stuff is omitted in PuTTYtel, or in a reconfig
2067 * when we're not doing SSH.
2070 if (backend_from_proto(PROT_SSH
) && (!midsession
|| protocol
== PROT_SSH
)) {
2073 * The Connection/SSH panel.
2075 ctrl_settitle(b
, "Connection/SSH",
2076 "Options controlling SSH connections");
2078 if (midsession
&& protcfginfo
== 1) {
2079 s
= ctrl_getset(b
, "Connection/SSH", "disclaimer", NULL
);
2080 ctrl_text(s
, "Nothing on this panel may be reconfigured in mid-"
2081 "session; it is only here so that sub-panels of it can "
2082 "exist without looking strange.", HELPCTX(no_help
));
2087 s
= ctrl_getset(b
, "Connection/SSH", "data",
2088 "Data to send to the server");
2089 ctrl_editbox(s
, "Remote command:", 'r', 100,
2090 HELPCTX(ssh_command
),
2091 conf_editbox_handler
, I(CONF_remote_cmd
), I(1));
2093 s
= ctrl_getset(b
, "Connection/SSH", "protocol", "Protocol options");
2094 ctrl_checkbox(s
, "Don't start a shell or command at all", 'n',
2095 HELPCTX(ssh_noshell
),
2096 conf_checkbox_handler
,
2097 I(CONF_ssh_no_shell
));
2100 if (!midsession
|| protcfginfo
!= 1) {
2101 s
= ctrl_getset(b
, "Connection/SSH", "protocol", "Protocol options");
2103 ctrl_checkbox(s
, "Enable compression", 'e',
2104 HELPCTX(ssh_compress
),
2105 conf_checkbox_handler
,
2106 I(CONF_compression
));
2110 s
= ctrl_getset(b
, "Connection/SSH", "protocol", "Protocol options");
2112 ctrl_radiobuttons(s
, "Preferred SSH protocol version:", NO_SHORTCUT
, 4,
2113 HELPCTX(ssh_protocol
),
2114 conf_radiobutton_handler
,
2116 "1 only", 'l', I(0),
2119 "2 only", 'y', I(3), NULL
);
2122 if (!midsession
|| protcfginfo
!= 1) {
2123 s
= ctrl_getset(b
, "Connection/SSH", "encryption", "Encryption options");
2124 c
= ctrl_draglist(s
, "Encryption cipher selection policy:", 's',
2125 HELPCTX(ssh_ciphers
),
2126 cipherlist_handler
, P(NULL
));
2127 c
->listbox
.height
= 6;
2129 ctrl_checkbox(s
, "Enable legacy use of single-DES in SSH-2", 'i',
2130 HELPCTX(ssh_ciphers
),
2131 conf_checkbox_handler
,
2132 I(CONF_ssh2_des_cbc
));
2136 * The Connection/SSH/Kex panel. (Owing to repeat key
2137 * exchange, this is all meaningful in mid-session _if_
2138 * we're using SSH-2 or haven't decided yet.)
2140 if (protcfginfo
!= 1) {
2141 ctrl_settitle(b
, "Connection/SSH/Kex",
2142 "Options controlling SSH key exchange");
2144 s
= ctrl_getset(b
, "Connection/SSH/Kex", "main",
2145 "Key exchange algorithm options");
2146 c
= ctrl_draglist(s
, "Algorithm selection policy:", 's',
2147 HELPCTX(ssh_kexlist
),
2148 kexlist_handler
, P(NULL
));
2149 c
->listbox
.height
= 5;
2151 s
= ctrl_getset(b
, "Connection/SSH/Kex", "repeat",
2152 "Options controlling key re-exchange");
2154 ctrl_editbox(s
, "Max minutes before rekey (0 for no limit)", 't', 20,
2155 HELPCTX(ssh_kex_repeat
),
2156 conf_editbox_handler
,
2157 I(CONF_ssh_rekey_time
),
2159 ctrl_editbox(s
, "Max data before rekey (0 for no limit)", 'x', 20,
2160 HELPCTX(ssh_kex_repeat
),
2161 conf_editbox_handler
,
2162 I(CONF_ssh_rekey_data
),
2164 ctrl_text(s
, "(Use 1M for 1 megabyte, 1G for 1 gigabyte etc)",
2165 HELPCTX(ssh_kex_repeat
));
2171 * The Connection/SSH/Auth panel.
2173 ctrl_settitle(b
, "Connection/SSH/Auth",
2174 "Options controlling SSH authentication");
2176 s
= ctrl_getset(b
, "Connection/SSH/Auth", "main", NULL
);
2177 ctrl_checkbox(s
, "Bypass authentication entirely (SSH-2 only)", 'b',
2178 HELPCTX(ssh_auth_bypass
),
2179 conf_checkbox_handler
,
2180 I(CONF_ssh_no_userauth
));
2181 ctrl_checkbox(s
, "Display pre-authentication banner (SSH-2 only)",
2182 'd', HELPCTX(ssh_auth_banner
),
2183 conf_checkbox_handler
,
2184 I(CONF_ssh_show_banner
));
2186 s
= ctrl_getset(b
, "Connection/SSH/Auth", "methods",
2187 "Authentication methods");
2188 ctrl_checkbox(s
, "Attempt authentication using Pageant", 'p',
2189 HELPCTX(ssh_auth_pageant
),
2190 conf_checkbox_handler
,
2192 ctrl_checkbox(s
, "Attempt TIS or CryptoCard auth (SSH-1)", 'm',
2193 HELPCTX(ssh_auth_tis
),
2194 conf_checkbox_handler
,
2195 I(CONF_try_tis_auth
));
2196 ctrl_checkbox(s
, "Attempt \"keyboard-interactive\" auth (SSH-2)",
2197 'i', HELPCTX(ssh_auth_ki
),
2198 conf_checkbox_handler
,
2199 I(CONF_try_ki_auth
));
2201 s
= ctrl_getset(b
, "Connection/SSH/Auth", "params",
2202 "Authentication parameters");
2203 ctrl_checkbox(s
, "Allow agent forwarding", 'f',
2204 HELPCTX(ssh_auth_agentfwd
),
2205 conf_checkbox_handler
, I(CONF_agentfwd
));
2206 ctrl_checkbox(s
, "Allow attempted changes of username in SSH-2", NO_SHORTCUT
,
2207 HELPCTX(ssh_auth_changeuser
),
2208 conf_checkbox_handler
,
2209 I(CONF_change_username
));
2210 ctrl_filesel(s
, "Private key file for authentication:", 'k',
2211 FILTER_KEY_FILES
, FALSE
, "Select private key file",
2212 HELPCTX(ssh_auth_privkey
),
2213 conf_filesel_handler
, I(CONF_keyfile
));
2217 * Connection/SSH/Auth/GSSAPI, which sadly won't fit on
2218 * the main Auth panel.
2220 ctrl_settitle(b
, "Connection/SSH/Auth/GSSAPI",
2221 "Options controlling GSSAPI authentication");
2222 s
= ctrl_getset(b
, "Connection/SSH/Auth/GSSAPI", "gssapi", NULL
);
2224 ctrl_checkbox(s
, "Attempt GSSAPI authentication (SSH-2 only)",
2225 't', HELPCTX(ssh_gssapi
),
2226 conf_checkbox_handler
,
2227 I(CONF_try_gssapi_auth
));
2229 ctrl_checkbox(s
, "Allow GSSAPI credential delegation", 'l',
2230 HELPCTX(ssh_gssapi_delegation
),
2231 conf_checkbox_handler
,
2235 * GSSAPI library selection.
2238 c
= ctrl_draglist(s
, "Preference order for GSSAPI libraries:",
2239 'p', HELPCTX(ssh_gssapi_libraries
),
2240 gsslist_handler
, P(NULL
));
2241 c
->listbox
.height
= ngsslibs
;
2244 * I currently assume that if more than one GSS
2245 * library option is available, then one of them is
2246 * 'user-supplied' and so we should present the
2247 * following file selector. This is at least half-
2248 * reasonable, because if we're using statically
2249 * linked GSSAPI then there will only be one option
2250 * and no way to load from a user-supplied library,
2251 * whereas if we're using dynamic libraries then
2252 * there will almost certainly be some default
2253 * option in addition to a user-supplied path. If
2254 * anyone ever ports PuTTY to a system on which
2255 * dynamic-library GSSAPI is available but there is
2256 * absolutely no consensus on where to keep the
2257 * libraries, there'll need to be a flag alongside
2258 * ngsslibs to control whether the file selector is
2262 ctrl_filesel(s
, "User-supplied GSSAPI library path:", 's',
2263 FILTER_DYNLIB_FILES
, FALSE
, "Select library file",
2264 HELPCTX(ssh_gssapi_libraries
),
2265 conf_filesel_handler
,
2266 I(CONF_ssh_gss_custom
));
2273 * The Connection/SSH/TTY panel.
2275 ctrl_settitle(b
, "Connection/SSH/TTY", "Remote terminal settings");
2277 s
= ctrl_getset(b
, "Connection/SSH/TTY", "sshtty", NULL
);
2278 ctrl_checkbox(s
, "Don't allocate a pseudo-terminal", 'p',
2280 conf_checkbox_handler
,
2283 s
= ctrl_getset(b
, "Connection/SSH/TTY", "ttymodes",
2285 td
= (struct ttymodes_data
*)
2286 ctrl_alloc(b
, sizeof(struct ttymodes_data
));
2287 ctrl_columns(s
, 2, 75, 25);
2288 c
= ctrl_text(s
, "Terminal modes to send:", HELPCTX(ssh_ttymodes
));
2289 c
->generic
.column
= 0;
2290 td
->rembutton
= ctrl_pushbutton(s
, "Remove", 'r',
2291 HELPCTX(ssh_ttymodes
),
2292 ttymodes_handler
, P(td
));
2293 td
->rembutton
->generic
.column
= 1;
2294 td
->rembutton
->generic
.tabdelay
= 1;
2295 ctrl_columns(s
, 1, 100);
2296 td
->listbox
= ctrl_listbox(s
, NULL
, NO_SHORTCUT
,
2297 HELPCTX(ssh_ttymodes
),
2298 ttymodes_handler
, P(td
));
2299 td
->listbox
->listbox
.multisel
= 1;
2300 td
->listbox
->listbox
.height
= 4;
2301 td
->listbox
->listbox
.ncols
= 2;
2302 td
->listbox
->listbox
.percentages
= snewn(2, int);
2303 td
->listbox
->listbox
.percentages
[0] = 40;
2304 td
->listbox
->listbox
.percentages
[1] = 60;
2305 ctrl_tabdelay(s
, td
->rembutton
);
2306 ctrl_columns(s
, 2, 75, 25);
2307 td
->modelist
= ctrl_droplist(s
, "Mode:", 'm', 67,
2308 HELPCTX(ssh_ttymodes
),
2309 ttymodes_handler
, P(td
));
2310 td
->modelist
->generic
.column
= 0;
2311 td
->addbutton
= ctrl_pushbutton(s
, "Add", 'd',
2312 HELPCTX(ssh_ttymodes
),
2313 ttymodes_handler
, P(td
));
2314 td
->addbutton
->generic
.column
= 1;
2315 td
->addbutton
->generic
.tabdelay
= 1;
2316 ctrl_columns(s
, 1, 100); /* column break */
2317 /* Bit of a hack to get the value radio buttons and
2318 * edit-box on the same row. */
2319 ctrl_columns(s
, 3, 25, 50, 25);
2320 c
= ctrl_text(s
, "Value:", HELPCTX(ssh_ttymodes
));
2321 c
->generic
.column
= 0;
2322 td
->valradio
= ctrl_radiobuttons(s
, NULL
, NO_SHORTCUT
, 2,
2323 HELPCTX(ssh_ttymodes
),
2324 ttymodes_handler
, P(td
),
2325 "Auto", NO_SHORTCUT
, P(NULL
),
2326 "This:", NO_SHORTCUT
, P(NULL
),
2328 td
->valradio
->generic
.column
= 1;
2329 td
->valbox
= ctrl_editbox(s
, NULL
, NO_SHORTCUT
, 100,
2330 HELPCTX(ssh_ttymodes
),
2331 ttymodes_handler
, P(td
), P(NULL
));
2332 td
->valbox
->generic
.column
= 2;
2333 ctrl_tabdelay(s
, td
->addbutton
);
2339 * The Connection/SSH/X11 panel.
2341 ctrl_settitle(b
, "Connection/SSH/X11",
2342 "Options controlling SSH X11 forwarding");
2344 s
= ctrl_getset(b
, "Connection/SSH/X11", "x11", "X11 forwarding");
2345 ctrl_checkbox(s
, "Enable X11 forwarding", 'e',
2346 HELPCTX(ssh_tunnels_x11
),
2347 conf_checkbox_handler
,I(CONF_x11_forward
));
2348 ctrl_editbox(s
, "X display location", 'x', 50,
2349 HELPCTX(ssh_tunnels_x11
),
2350 conf_editbox_handler
, I(CONF_x11_display
), I(1));
2351 ctrl_radiobuttons(s
, "Remote X11 authentication protocol", 'u', 2,
2352 HELPCTX(ssh_tunnels_x11auth
),
2353 conf_radiobutton_handler
,
2355 "MIT-Magic-Cookie-1", I(X11_MIT
),
2356 "XDM-Authorization-1", I(X11_XDM
), NULL
);
2360 * The Tunnels panel _is_ still available in mid-session.
2362 ctrl_settitle(b
, "Connection/SSH/Tunnels",
2363 "Options controlling SSH port forwarding");
2365 s
= ctrl_getset(b
, "Connection/SSH/Tunnels", "portfwd",
2367 ctrl_checkbox(s
, "Local ports accept connections from other hosts",'t',
2368 HELPCTX(ssh_tunnels_portfwd_localhost
),
2369 conf_checkbox_handler
,
2370 I(CONF_lport_acceptall
));
2371 ctrl_checkbox(s
, "Remote ports do the same (SSH-2 only)", 'p',
2372 HELPCTX(ssh_tunnels_portfwd_localhost
),
2373 conf_checkbox_handler
,
2374 I(CONF_rport_acceptall
));
2376 ctrl_columns(s
, 3, 55, 20, 25);
2377 c
= ctrl_text(s
, "Forwarded ports:", HELPCTX(ssh_tunnels_portfwd
));
2378 c
->generic
.column
= COLUMN_FIELD(0,2);
2379 /* You want to select from the list, _then_ hit Remove. So tab order
2380 * should be that way round. */
2381 pfd
= (struct portfwd_data
*)ctrl_alloc(b
,sizeof(struct portfwd_data
));
2382 pfd
->rembutton
= ctrl_pushbutton(s
, "Remove", 'r',
2383 HELPCTX(ssh_tunnels_portfwd
),
2384 portfwd_handler
, P(pfd
));
2385 pfd
->rembutton
->generic
.column
= 2;
2386 pfd
->rembutton
->generic
.tabdelay
= 1;
2387 pfd
->listbox
= ctrl_listbox(s
, NULL
, NO_SHORTCUT
,
2388 HELPCTX(ssh_tunnels_portfwd
),
2389 portfwd_handler
, P(pfd
));
2390 pfd
->listbox
->listbox
.height
= 3;
2391 pfd
->listbox
->listbox
.ncols
= 2;
2392 pfd
->listbox
->listbox
.percentages
= snewn(2, int);
2393 pfd
->listbox
->listbox
.percentages
[0] = 20;
2394 pfd
->listbox
->listbox
.percentages
[1] = 80;
2395 ctrl_tabdelay(s
, pfd
->rembutton
);
2396 ctrl_text(s
, "Add new forwarded port:", HELPCTX(ssh_tunnels_portfwd
));
2397 /* You want to enter source, destination and type, _then_ hit Add.
2398 * Again, we adjust the tab order to reflect this. */
2399 pfd
->addbutton
= ctrl_pushbutton(s
, "Add", 'd',
2400 HELPCTX(ssh_tunnels_portfwd
),
2401 portfwd_handler
, P(pfd
));
2402 pfd
->addbutton
->generic
.column
= 2;
2403 pfd
->addbutton
->generic
.tabdelay
= 1;
2404 pfd
->sourcebox
= ctrl_editbox(s
, "Source port", 's', 40,
2405 HELPCTX(ssh_tunnels_portfwd
),
2406 portfwd_handler
, P(pfd
), P(NULL
));
2407 pfd
->sourcebox
->generic
.column
= 0;
2408 pfd
->destbox
= ctrl_editbox(s
, "Destination", 'i', 67,
2409 HELPCTX(ssh_tunnels_portfwd
),
2410 portfwd_handler
, P(pfd
), P(NULL
));
2411 pfd
->direction
= ctrl_radiobuttons(s
, NULL
, NO_SHORTCUT
, 3,
2412 HELPCTX(ssh_tunnels_portfwd
),
2413 portfwd_handler
, P(pfd
),
2414 "Local", 'l', P(NULL
),
2415 "Remote", 'm', P(NULL
),
2416 "Dynamic", 'y', P(NULL
),
2419 pfd
->addressfamily
=
2420 ctrl_radiobuttons(s
, NULL
, NO_SHORTCUT
, 3,
2421 HELPCTX(ssh_tunnels_portfwd_ipversion
),
2422 portfwd_handler
, P(pfd
),
2423 "Auto", 'u', I(ADDRTYPE_UNSPEC
),
2424 "IPv4", '4', I(ADDRTYPE_IPV4
),
2425 "IPv6", '6', I(ADDRTYPE_IPV6
),
2428 ctrl_tabdelay(s
, pfd
->addbutton
);
2429 ctrl_columns(s
, 1, 100);
2433 * The Connection/SSH/Bugs panel.
2435 ctrl_settitle(b
, "Connection/SSH/Bugs",
2436 "Workarounds for SSH server bugs");
2438 s
= ctrl_getset(b
, "Connection/SSH/Bugs", "main",
2439 "Detection of known bugs in SSH servers");
2440 ctrl_droplist(s
, "Chokes on SSH-1 ignore messages", 'i', 20,
2441 HELPCTX(ssh_bugs_ignore1
),
2442 sshbug_handler
, I(CONF_sshbug_ignore1
));
2443 ctrl_droplist(s
, "Refuses all SSH-1 password camouflage", 's', 20,
2444 HELPCTX(ssh_bugs_plainpw1
),
2445 sshbug_handler
, I(CONF_sshbug_plainpw1
));
2446 ctrl_droplist(s
, "Chokes on SSH-1 RSA authentication", 'r', 20,
2447 HELPCTX(ssh_bugs_rsa1
),
2448 sshbug_handler
, I(CONF_sshbug_rsa1
));
2449 ctrl_droplist(s
, "Chokes on SSH-2 ignore messages", '2', 20,
2450 HELPCTX(ssh_bugs_ignore2
),
2451 sshbug_handler
, I(CONF_sshbug_ignore2
));
2452 ctrl_droplist(s
, "Miscomputes SSH-2 HMAC keys", 'm', 20,
2453 HELPCTX(ssh_bugs_hmac2
),
2454 sshbug_handler
, I(CONF_sshbug_hmac2
));
2455 ctrl_droplist(s
, "Miscomputes SSH-2 encryption keys", 'e', 20,
2456 HELPCTX(ssh_bugs_derivekey2
),
2457 sshbug_handler
, I(CONF_sshbug_derivekey2
));
2458 ctrl_droplist(s
, "Requires padding on SSH-2 RSA signatures", 'p', 20,
2459 HELPCTX(ssh_bugs_rsapad2
),
2460 sshbug_handler
, I(CONF_sshbug_rsapad2
));
2461 ctrl_droplist(s
, "Misuses the session ID in SSH-2 PK auth", 'n', 20,
2462 HELPCTX(ssh_bugs_pksessid2
),
2463 sshbug_handler
, I(CONF_sshbug_pksessid2
));
2464 ctrl_droplist(s
, "Handles SSH-2 key re-exchange badly", 'k', 20,
2465 HELPCTX(ssh_bugs_rekey2
),
2466 sshbug_handler
, I(CONF_sshbug_rekey2
));
2467 ctrl_droplist(s
, "Ignores SSH-2 maximum packet size", 'x', 20,
2468 HELPCTX(ssh_bugs_maxpkt2
),
2469 sshbug_handler
, I(CONF_sshbug_maxpkt2
));