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"
19 * Convenience function: determine whether this binary supports a
22 static int have_backend(int protocol
)
24 struct backend_list
*p
= backends
;
25 for (p
= backends
; p
->name
; p
++) {
26 if (p
->protocol
== protocol
)
32 static void config_host_handler(union control
*ctrl
, void *dlg
,
33 void *data
, int event
)
35 Config
*cfg
= (Config
*)data
;
38 * This function works just like the standard edit box handler,
39 * only it has to choose the control's label and text from two
40 * different places depending on the protocol.
42 if (event
== EVENT_REFRESH
) {
43 if (cfg
->protocol
== PROT_SERIAL
) {
45 * This label text is carefully chosen to contain an n,
46 * since that's the shortcut for the host name control.
48 dlg_label_change(ctrl
, dlg
, "Serial line");
49 dlg_editbox_set(ctrl
, dlg
, cfg
->serline
);
51 dlg_label_change(ctrl
, dlg
, HOST_BOX_TITLE
);
52 dlg_editbox_set(ctrl
, dlg
, cfg
->host
);
54 } else if (event
== EVENT_VALCHANGE
) {
55 if (cfg
->protocol
== PROT_SERIAL
)
56 dlg_editbox_get(ctrl
, dlg
, cfg
->serline
, lenof(cfg
->serline
));
58 dlg_editbox_get(ctrl
, dlg
, cfg
->host
, lenof(cfg
->host
));
62 static void config_port_handler(union control
*ctrl
, void *dlg
,
63 void *data
, int event
)
65 Config
*cfg
= (Config
*)data
;
69 * This function works just like the standard edit box handler,
70 * only it has to choose the control's label and text from two
71 * different places depending on the protocol.
73 if (event
== EVENT_REFRESH
) {
74 if (cfg
->protocol
== PROT_SERIAL
) {
76 * This label text is carefully chosen to contain a p,
77 * since that's the shortcut for the port control.
79 dlg_label_change(ctrl
, dlg
, "Speed");
80 sprintf(buf
, "%d", cfg
->serspeed
);
82 dlg_label_change(ctrl
, dlg
, PORT_BOX_TITLE
);
83 sprintf(buf
, "%d", cfg
->port
);
85 dlg_editbox_set(ctrl
, dlg
, buf
);
86 } else if (event
== EVENT_VALCHANGE
) {
87 dlg_editbox_get(ctrl
, dlg
, buf
, lenof(buf
));
88 if (cfg
->protocol
== PROT_SERIAL
)
89 cfg
->serspeed
= atoi(buf
);
91 cfg
->port
= atoi(buf
);
96 union control
*host
, *port
;
100 * We export this function so that platform-specific config
101 * routines can use it to conveniently identify the protocol radio
102 * buttons in order to add to them.
104 void config_protocolbuttons_handler(union control
*ctrl
, void *dlg
,
105 void *data
, int event
)
108 Config
*cfg
= (Config
*)data
;
109 struct hostport
*hp
= (struct hostport
*)ctrl
->radio
.context
.p
;
112 * This function works just like the standard radio-button
113 * handler, except that it also has to change the setting of
114 * the port box, and refresh both host and port boxes when. We
115 * expect the context parameter to point at a hostport
116 * structure giving the `union control's for both.
118 if (event
== EVENT_REFRESH
) {
119 for (button
= 0; button
< ctrl
->radio
.nbuttons
; button
++)
120 if (cfg
->protocol
== ctrl
->radio
.buttondata
[button
].i
)
122 /* We expected that `break' to happen, in all circumstances. */
123 assert(button
< ctrl
->radio
.nbuttons
);
124 dlg_radiobutton_set(ctrl
, dlg
, button
);
125 } else if (event
== EVENT_VALCHANGE
) {
126 int oldproto
= cfg
->protocol
;
127 button
= dlg_radiobutton_get(ctrl
, dlg
);
128 assert(button
>= 0 && button
< ctrl
->radio
.nbuttons
);
129 cfg
->protocol
= ctrl
->radio
.buttondata
[button
].i
;
130 if (oldproto
!= cfg
->protocol
) {
132 switch (cfg
->protocol
) {
133 case PROT_SSH
: defport
= 22; break;
134 case PROT_TELNET
: defport
= 23; break;
135 case PROT_RLOGIN
: defport
= 513; break;
137 if (defport
> 0 && cfg
->port
!= defport
) {
141 dlg_refresh(hp
->host
, dlg
);
142 dlg_refresh(hp
->port
, dlg
);
146 static void loggingbuttons_handler(union control
*ctrl
, void *dlg
,
147 void *data
, int event
)
150 Config
*cfg
= (Config
*)data
;
151 /* This function works just like the standard radio-button handler,
152 * but it has to fall back to "no logging" in situations where the
153 * configured logging type isn't applicable.
155 if (event
== EVENT_REFRESH
) {
156 for (button
= 0; button
< ctrl
->radio
.nbuttons
; button
++)
157 if (cfg
->logtype
== ctrl
->radio
.buttondata
[button
].i
)
160 /* We fell off the end, so we lack the configured logging type */
161 if (button
== ctrl
->radio
.nbuttons
) {
163 cfg
->logtype
=LGTYP_NONE
;
165 dlg_radiobutton_set(ctrl
, dlg
, button
);
166 } else if (event
== EVENT_VALCHANGE
) {
167 button
= dlg_radiobutton_get(ctrl
, dlg
);
168 assert(button
>= 0 && button
< ctrl
->radio
.nbuttons
);
169 cfg
->logtype
= ctrl
->radio
.buttondata
[button
].i
;
173 static void numeric_keypad_handler(union control
*ctrl
, void *dlg
,
174 void *data
, int event
)
177 Config
*cfg
= (Config
*)data
;
179 * This function works much like the standard radio button
180 * handler, but it has to handle two fields in Config.
182 if (event
== EVENT_REFRESH
) {
183 if (cfg
->nethack_keypad
)
185 else if (cfg
->app_keypad
)
189 assert(button
< ctrl
->radio
.nbuttons
);
190 dlg_radiobutton_set(ctrl
, dlg
, button
);
191 } else if (event
== EVENT_VALCHANGE
) {
192 button
= dlg_radiobutton_get(ctrl
, dlg
);
193 assert(button
>= 0 && button
< ctrl
->radio
.nbuttons
);
195 cfg
->app_keypad
= FALSE
;
196 cfg
->nethack_keypad
= TRUE
;
198 cfg
->app_keypad
= (button
!= 0);
199 cfg
->nethack_keypad
= FALSE
;
204 static void cipherlist_handler(union control
*ctrl
, void *dlg
,
205 void *data
, int event
)
207 Config
*cfg
= (Config
*)data
;
208 if (event
== EVENT_REFRESH
) {
211 static const struct { char *s
; int c
; } ciphers
[] = {
212 { "3DES", CIPHER_3DES
},
213 { "Blowfish", CIPHER_BLOWFISH
},
214 { "DES", CIPHER_DES
},
215 { "AES (SSH-2 only)", CIPHER_AES
},
216 { "Arcfour (SSH-2 only)", CIPHER_ARCFOUR
},
217 { "-- warn below here --", CIPHER_WARN
}
220 /* Set up the "selected ciphers" box. */
221 /* (cipherlist assumed to contain all ciphers) */
222 dlg_update_start(ctrl
, dlg
);
223 dlg_listbox_clear(ctrl
, dlg
);
224 for (i
= 0; i
< CIPHER_MAX
; i
++) {
225 int c
= cfg
->ssh_cipherlist
[i
];
228 for (j
= 0; j
< (sizeof ciphers
) / (sizeof ciphers
[0]); j
++) {
229 if (ciphers
[j
].c
== c
) {
234 dlg_listbox_addwithid(ctrl
, dlg
, cstr
, c
);
236 dlg_update_done(ctrl
, dlg
);
238 } else if (event
== EVENT_VALCHANGE
) {
241 /* Update array to match the list box. */
242 for (i
=0; i
< CIPHER_MAX
; i
++)
243 cfg
->ssh_cipherlist
[i
] = dlg_listbox_getid(ctrl
, dlg
, i
);
248 static void kexlist_handler(union control
*ctrl
, void *dlg
,
249 void *data
, int event
)
251 Config
*cfg
= (Config
*)data
;
252 if (event
== EVENT_REFRESH
) {
255 static const struct { char *s
; int k
; } kexes
[] = {
256 { "Diffie-Hellman group 1", KEX_DHGROUP1
},
257 { "Diffie-Hellman group 14", KEX_DHGROUP14
},
258 { "Diffie-Hellman group exchange", KEX_DHGEX
},
259 { "-- warn below here --", KEX_WARN
}
262 /* Set up the "kex preference" box. */
263 /* (kexlist assumed to contain all algorithms) */
264 dlg_update_start(ctrl
, dlg
);
265 dlg_listbox_clear(ctrl
, dlg
);
266 for (i
= 0; i
< KEX_MAX
; i
++) {
267 int k
= cfg
->ssh_kexlist
[i
];
270 for (j
= 0; j
< (sizeof kexes
) / (sizeof kexes
[0]); j
++) {
271 if (kexes
[j
].k
== k
) {
276 dlg_listbox_addwithid(ctrl
, dlg
, kstr
, k
);
278 dlg_update_done(ctrl
, dlg
);
280 } else if (event
== EVENT_VALCHANGE
) {
283 /* Update array to match the list box. */
284 for (i
=0; i
< KEX_MAX
; i
++)
285 cfg
->ssh_kexlist
[i
] = dlg_listbox_getid(ctrl
, dlg
, i
);
290 static void printerbox_handler(union control
*ctrl
, void *dlg
,
291 void *data
, int event
)
293 Config
*cfg
= (Config
*)data
;
294 if (event
== EVENT_REFRESH
) {
298 dlg_update_start(ctrl
, dlg
);
300 * Some backends may wish to disable the drop-down list on
301 * this edit box. Be prepared for this.
303 if (ctrl
->editbox
.has_list
) {
304 dlg_listbox_clear(ctrl
, dlg
);
305 dlg_listbox_add(ctrl
, dlg
, PRINTER_DISABLED_STRING
);
306 pe
= printer_start_enum(&nprinters
);
307 for (i
= 0; i
< nprinters
; i
++)
308 dlg_listbox_add(ctrl
, dlg
, printer_get_name(pe
, i
));
309 printer_finish_enum(pe
);
311 dlg_editbox_set(ctrl
, dlg
,
312 (*cfg
->printer ? cfg
->printer
:
313 PRINTER_DISABLED_STRING
));
314 dlg_update_done(ctrl
, dlg
);
315 } else if (event
== EVENT_VALCHANGE
) {
316 dlg_editbox_get(ctrl
, dlg
, cfg
->printer
, sizeof(cfg
->printer
));
317 if (!strcmp(cfg
->printer
, PRINTER_DISABLED_STRING
))
318 *cfg
->printer
= '\0';
322 static void codepage_handler(union control
*ctrl
, void *dlg
,
323 void *data
, int event
)
325 Config
*cfg
= (Config
*)data
;
326 if (event
== EVENT_REFRESH
) {
329 dlg_update_start(ctrl
, dlg
);
330 strcpy(cfg
->line_codepage
,
331 cp_name(decode_codepage(cfg
->line_codepage
)));
332 dlg_listbox_clear(ctrl
, dlg
);
333 for (i
= 0; (cp
= cp_enumerate(i
)) != NULL
; i
++)
334 dlg_listbox_add(ctrl
, dlg
, cp
);
335 dlg_editbox_set(ctrl
, dlg
, cfg
->line_codepage
);
336 dlg_update_done(ctrl
, dlg
);
337 } else if (event
== EVENT_VALCHANGE
) {
338 dlg_editbox_get(ctrl
, dlg
, cfg
->line_codepage
,
339 sizeof(cfg
->line_codepage
));
340 strcpy(cfg
->line_codepage
,
341 cp_name(decode_codepage(cfg
->line_codepage
)));
345 static void sshbug_handler(union control
*ctrl
, void *dlg
,
346 void *data
, int event
)
348 if (event
== EVENT_REFRESH
) {
349 dlg_update_start(ctrl
, dlg
);
350 dlg_listbox_clear(ctrl
, dlg
);
351 dlg_listbox_addwithid(ctrl
, dlg
, "Auto", AUTO
);
352 dlg_listbox_addwithid(ctrl
, dlg
, "Off", FORCE_OFF
);
353 dlg_listbox_addwithid(ctrl
, dlg
, "On", FORCE_ON
);
354 switch (*(int *)ATOFFSET(data
, ctrl
->listbox
.context
.i
)) {
355 case AUTO
: dlg_listbox_select(ctrl
, dlg
, 0); break;
356 case FORCE_OFF
: dlg_listbox_select(ctrl
, dlg
, 1); break;
357 case FORCE_ON
: dlg_listbox_select(ctrl
, dlg
, 2); break;
359 dlg_update_done(ctrl
, dlg
);
360 } else if (event
== EVENT_SELCHANGE
) {
361 int i
= dlg_listbox_index(ctrl
, dlg
);
365 i
= dlg_listbox_getid(ctrl
, dlg
, i
);
366 *(int *)ATOFFSET(data
, ctrl
->listbox
.context
.i
) = i
;
370 #define SAVEDSESSION_LEN 2048
372 struct sessionsaver_data
{
373 union control
*editbox
, *listbox
, *loadbutton
, *savebutton
, *delbutton
;
374 union control
*okbutton
, *cancelbutton
;
375 struct sesslist sesslist
;
380 * Helper function to load the session selected in the list box, if
381 * any, as this is done in more than one place below. Returns 0 for
384 static int load_selected_session(struct sessionsaver_data
*ssd
,
386 void *dlg
, Config
*cfg
)
388 int i
= dlg_listbox_index(ssd
->listbox
, dlg
);
394 isdef
= !strcmp(ssd
->sesslist
.sessions
[i
], "Default Settings");
395 load_settings(ssd
->sesslist
.sessions
[i
], !isdef
, cfg
);
397 strncpy(savedsession
, ssd
->sesslist
.sessions
[i
],
399 savedsession
[SAVEDSESSION_LEN
-1] = '\0';
401 savedsession
[0] = '\0';
403 dlg_refresh(NULL
, dlg
);
404 /* Restore the selection, which might have been clobbered by
405 * changing the value of the edit box. */
406 dlg_listbox_select(ssd
->listbox
, dlg
, i
);
410 static void sessionsaver_handler(union control
*ctrl
, void *dlg
,
411 void *data
, int event
)
413 Config
*cfg
= (Config
*)data
;
414 struct sessionsaver_data
*ssd
=
415 (struct sessionsaver_data
*)ctrl
->generic
.context
.p
;
419 * The first time we're called in a new dialog, we must
420 * allocate space to store the current contents of the saved
421 * session edit box (since it must persist even when we switch
422 * panels, but is not part of the Config).
426 } else if (!dlg_get_privdata(ssd
->editbox
, dlg
)) {
427 savedsession
= (char *)
428 dlg_alloc_privdata(ssd
->editbox
, dlg
, SAVEDSESSION_LEN
);
429 savedsession
[0] = '\0';
431 savedsession
= dlg_get_privdata(ssd
->editbox
, dlg
);
434 if (event
== EVENT_REFRESH
) {
435 if (ctrl
== ssd
->editbox
) {
436 dlg_editbox_set(ctrl
, dlg
, savedsession
);
437 } else if (ctrl
== ssd
->listbox
) {
439 dlg_update_start(ctrl
, dlg
);
440 dlg_listbox_clear(ctrl
, dlg
);
441 for (i
= 0; i
< ssd
->sesslist
.nsessions
; i
++)
442 dlg_listbox_add(ctrl
, dlg
, ssd
->sesslist
.sessions
[i
]);
443 dlg_update_done(ctrl
, dlg
);
445 } else if (event
== EVENT_VALCHANGE
) {
446 int top
, bottom
, halfway
, i
;
447 if (ctrl
== ssd
->editbox
) {
448 dlg_editbox_get(ctrl
, dlg
, savedsession
,
450 top
= ssd
->sesslist
.nsessions
;
452 while (top
-bottom
> 1) {
453 halfway
= (top
+bottom
)/2;
454 i
= strcmp(savedsession
, ssd
->sesslist
.sessions
[halfway
]);
461 if (top
== ssd
->sesslist
.nsessions
) {
464 dlg_listbox_select(ssd
->listbox
, dlg
, top
);
466 } else if (event
== EVENT_ACTION
) {
467 if (!ssd
->midsession
&&
468 (ctrl
== ssd
->listbox
||
469 (ssd
->loadbutton
&& ctrl
== ssd
->loadbutton
))) {
471 * The user has double-clicked a session, or hit Load.
472 * We must load the selected session, and then
473 * terminate the configuration dialog _if_ there was a
474 * double-click on the list box _and_ that session
475 * contains a hostname.
477 if (load_selected_session(ssd
, savedsession
, dlg
, cfg
) &&
478 (ctrl
== ssd
->listbox
&& cfg_launchable(cfg
))) {
479 dlg_end(dlg
, 1); /* it's all over, and succeeded */
481 } else if (ctrl
== ssd
->savebutton
) {
482 int isdef
= !strcmp(savedsession
, "Default Settings");
483 if (!savedsession
[0]) {
484 int i
= dlg_listbox_index(ssd
->listbox
, dlg
);
489 isdef
= !strcmp(ssd
->sesslist
.sessions
[i
], "Default Settings");
491 strncpy(savedsession
, ssd
->sesslist
.sessions
[i
],
493 savedsession
[SAVEDSESSION_LEN
-1] = '\0';
495 savedsession
[0] = '\0';
499 char *errmsg
= save_settings(savedsession
, !isdef
, cfg
);
501 dlg_error_msg(dlg
, errmsg
);
505 get_sesslist(&ssd
->sesslist
, FALSE
);
506 get_sesslist(&ssd
->sesslist
, TRUE
);
507 dlg_refresh(ssd
->editbox
, dlg
);
508 dlg_refresh(ssd
->listbox
, dlg
);
509 } else if (!ssd
->midsession
&&
510 ssd
->delbutton
&& ctrl
== ssd
->delbutton
) {
511 int i
= dlg_listbox_index(ssd
->listbox
, dlg
);
515 del_settings(ssd
->sesslist
.sessions
[i
]);
516 get_sesslist(&ssd
->sesslist
, FALSE
);
517 get_sesslist(&ssd
->sesslist
, TRUE
);
518 dlg_refresh(ssd
->listbox
, dlg
);
520 } else if (ctrl
== ssd
->okbutton
) {
521 if (ssd
->midsession
) {
522 /* In a mid-session Change Settings, Apply is always OK. */
527 * Annoying special case. If the `Open' button is
528 * pressed while no host name is currently set, _and_
529 * the session list previously had the focus, _and_
530 * there was a session selected in that which had a
531 * valid host name in it, then load it and go.
533 if (dlg_last_focused(ctrl
, dlg
) == ssd
->listbox
&&
534 !cfg_launchable(cfg
)) {
536 if (!load_selected_session(ssd
, savedsession
, dlg
, &cfg2
)) {
540 /* If at this point we have a valid session, go! */
542 *cfg
= cfg2
; /* structure copy */
543 cfg
->remote_cmd_ptr
= NULL
;
551 * Otherwise, do the normal thing: if we have a valid
552 * session, get going.
554 if (cfg_launchable(cfg
)) {
558 } else if (ctrl
== ssd
->cancelbutton
) {
564 struct charclass_data
{
565 union control
*listbox
, *editbox
, *button
;
568 static void charclass_handler(union control
*ctrl
, void *dlg
,
569 void *data
, int event
)
571 Config
*cfg
= (Config
*)data
;
572 struct charclass_data
*ccd
=
573 (struct charclass_data
*)ctrl
->generic
.context
.p
;
575 if (event
== EVENT_REFRESH
) {
576 if (ctrl
== ccd
->listbox
) {
578 dlg_update_start(ctrl
, dlg
);
579 dlg_listbox_clear(ctrl
, dlg
);
580 for (i
= 0; i
< 128; i
++) {
582 sprintf(str
, "%d\t(0x%02X)\t%c\t%d", i
, i
,
583 (i
>= 0x21 && i
!= 0x7F) ? i
: ' ', cfg
->wordness
[i
]);
584 dlg_listbox_add(ctrl
, dlg
, str
);
586 dlg_update_done(ctrl
, dlg
);
588 } else if (event
== EVENT_ACTION
) {
589 if (ctrl
== ccd
->button
) {
592 dlg_editbox_get(ccd
->editbox
, dlg
, str
, sizeof(str
));
594 for (i
= 0; i
< 128; i
++) {
595 if (dlg_listbox_issel(ccd
->listbox
, dlg
, i
))
596 cfg
->wordness
[i
] = n
;
598 dlg_refresh(ccd
->listbox
, dlg
);
604 union control
*listbox
, *redit
, *gedit
, *bedit
, *button
;
607 static const char *const colours
[] = {
608 "Default Foreground", "Default Bold Foreground",
609 "Default Background", "Default Bold Background",
610 "Cursor Text", "Cursor Colour",
611 "ANSI Black", "ANSI Black Bold",
612 "ANSI Red", "ANSI Red Bold",
613 "ANSI Green", "ANSI Green Bold",
614 "ANSI Yellow", "ANSI Yellow Bold",
615 "ANSI Blue", "ANSI Blue Bold",
616 "ANSI Magenta", "ANSI Magenta Bold",
617 "ANSI Cyan", "ANSI Cyan Bold",
618 "ANSI White", "ANSI White Bold"
621 static void colour_handler(union control
*ctrl
, void *dlg
,
622 void *data
, int event
)
624 Config
*cfg
= (Config
*)data
;
625 struct colour_data
*cd
=
626 (struct colour_data
*)ctrl
->generic
.context
.p
;
627 int update
= FALSE
, r
, g
, b
;
629 if (event
== EVENT_REFRESH
) {
630 if (ctrl
== cd
->listbox
) {
632 dlg_update_start(ctrl
, dlg
);
633 dlg_listbox_clear(ctrl
, dlg
);
634 for (i
= 0; i
< lenof(colours
); i
++)
635 dlg_listbox_add(ctrl
, dlg
, colours
[i
]);
636 dlg_update_done(ctrl
, dlg
);
637 dlg_editbox_set(cd
->redit
, dlg
, "");
638 dlg_editbox_set(cd
->gedit
, dlg
, "");
639 dlg_editbox_set(cd
->bedit
, dlg
, "");
641 } else if (event
== EVENT_SELCHANGE
) {
642 if (ctrl
== cd
->listbox
) {
643 /* The user has selected a colour. Update the RGB text. */
644 int i
= dlg_listbox_index(ctrl
, dlg
);
649 r
= cfg
->colours
[i
][0];
650 g
= cfg
->colours
[i
][1];
651 b
= cfg
->colours
[i
][2];
654 } else if (event
== EVENT_VALCHANGE
) {
655 if (ctrl
== cd
->redit
|| ctrl
== cd
->gedit
|| ctrl
== cd
->bedit
) {
656 /* The user has changed the colour using the edit boxes. */
660 dlg_editbox_get(ctrl
, dlg
, buf
, lenof(buf
));
662 if (cval
> 255) cval
= 255;
663 if (cval
< 0) cval
= 0;
665 i
= dlg_listbox_index(cd
->listbox
, dlg
);
667 if (ctrl
== cd
->redit
)
668 cfg
->colours
[i
][0] = cval
;
669 else if (ctrl
== cd
->gedit
)
670 cfg
->colours
[i
][1] = cval
;
671 else if (ctrl
== cd
->bedit
)
672 cfg
->colours
[i
][2] = cval
;
675 } else if (event
== EVENT_ACTION
) {
676 if (ctrl
== cd
->button
) {
677 int i
= dlg_listbox_index(cd
->listbox
, dlg
);
683 * Start a colour selector, which will send us an
684 * EVENT_CALLBACK when it's finished and allow us to
685 * pick up the results.
687 dlg_coloursel_start(ctrl
, dlg
,
692 } else if (event
== EVENT_CALLBACK
) {
693 if (ctrl
== cd
->button
) {
694 int i
= dlg_listbox_index(cd
->listbox
, dlg
);
696 * Collect the results of the colour selector. Will
697 * return nonzero on success, or zero if the colour
698 * selector did nothing (user hit Cancel, for example).
700 if (dlg_coloursel_results(ctrl
, dlg
, &r
, &g
, &b
)) {
701 cfg
->colours
[i
][0] = r
;
702 cfg
->colours
[i
][1] = g
;
703 cfg
->colours
[i
][2] = b
;
711 sprintf(buf
, "%d", r
); dlg_editbox_set(cd
->redit
, dlg
, buf
);
712 sprintf(buf
, "%d", g
); dlg_editbox_set(cd
->gedit
, dlg
, buf
);
713 sprintf(buf
, "%d", b
); dlg_editbox_set(cd
->bedit
, dlg
, buf
);
717 struct ttymodes_data
{
718 union control
*modelist
, *valradio
, *valbox
;
719 union control
*addbutton
, *rembutton
, *listbox
;
722 static void ttymodes_handler(union control
*ctrl
, void *dlg
,
723 void *data
, int event
)
725 Config
*cfg
= (Config
*)data
;
726 struct ttymodes_data
*td
=
727 (struct ttymodes_data
*)ctrl
->generic
.context
.p
;
729 if (event
== EVENT_REFRESH
) {
730 if (ctrl
== td
->listbox
) {
731 char *p
= cfg
->ttymodes
;
732 dlg_update_start(ctrl
, dlg
);
733 dlg_listbox_clear(ctrl
, dlg
);
735 int tabpos
= strchr(p
, '\t') - p
;
736 char *disp
= dupprintf("%.*s\t%s", tabpos
, p
,
737 (p
[tabpos
+1] == 'A') ?
"(auto)" :
739 dlg_listbox_add(ctrl
, dlg
, disp
);
743 dlg_update_done(ctrl
, dlg
);
744 } else if (ctrl
== td
->modelist
) {
746 dlg_update_start(ctrl
, dlg
);
747 dlg_listbox_clear(ctrl
, dlg
);
748 for (i
= 0; ttymodes
[i
]; i
++)
749 dlg_listbox_add(ctrl
, dlg
, ttymodes
[i
]);
750 dlg_listbox_select(ctrl
, dlg
, 0); /* *shrug* */
751 dlg_update_done(ctrl
, dlg
);
752 } else if (ctrl
== td
->valradio
) {
753 dlg_radiobutton_set(ctrl
, dlg
, 0);
755 } else if (event
== EVENT_ACTION
) {
756 if (ctrl
== td
->addbutton
) {
757 int ind
= dlg_listbox_index(td
->modelist
, dlg
);
759 char type
= dlg_radiobutton_get(td
->valradio
, dlg
) ?
'V' : 'A';
761 char *p
, str
[lenof(cfg
->ttymodes
)];
762 /* Construct new entry */
763 memset(str
, 0, lenof(str
));
764 strncpy(str
, ttymodes
[ind
], lenof(str
)-3);
770 dlg_editbox_get(td
->valbox
, dlg
, str
+slen
, lenof(str
)-slen
);
772 /* Find end of list, deleting any existing instance */
774 left
= lenof(cfg
->ttymodes
);
776 int t
= strchr(p
, '\t') - p
;
777 if (t
== strlen(ttymodes
[ind
]) &&
778 strncmp(p
, ttymodes
[ind
], t
) == 0) {
779 memmove(p
, p
+strlen(p
)+1, left
- (strlen(p
)+1));
782 left
-= strlen(p
) + 1;
785 /* Append new entry */
787 strncpy(p
, str
, left
- 2);
788 dlg_refresh(td
->listbox
, dlg
);
791 } else if (ctrl
== td
->rembutton
) {
792 char *p
= cfg
->ttymodes
;
793 int i
= 0, len
= lenof(cfg
->ttymodes
);
795 if (dlg_listbox_issel(td
->listbox
, dlg
, i
)) {
796 memmove(p
, p
+strlen(p
)+1, len
- (strlen(p
)+1));
800 len
-= strlen(p
) + 1;
804 memset(p
, 0, lenof(cfg
->ttymodes
) - len
);
805 dlg_refresh(td
->listbox
, dlg
);
810 struct environ_data
{
811 union control
*varbox
, *valbox
, *addbutton
, *rembutton
, *listbox
;
814 static void environ_handler(union control
*ctrl
, void *dlg
,
815 void *data
, int event
)
817 Config
*cfg
= (Config
*)data
;
818 struct environ_data
*ed
=
819 (struct environ_data
*)ctrl
->generic
.context
.p
;
821 if (event
== EVENT_REFRESH
) {
822 if (ctrl
== ed
->listbox
) {
823 char *p
= cfg
->environmt
;
824 dlg_update_start(ctrl
, dlg
);
825 dlg_listbox_clear(ctrl
, dlg
);
827 dlg_listbox_add(ctrl
, dlg
, p
);
830 dlg_update_done(ctrl
, dlg
);
832 } else if (event
== EVENT_ACTION
) {
833 if (ctrl
== ed
->addbutton
) {
834 char str
[sizeof(cfg
->environmt
)];
836 dlg_editbox_get(ed
->varbox
, dlg
, str
, sizeof(str
)-1);
841 p
= str
+ strlen(str
);
843 dlg_editbox_get(ed
->valbox
, dlg
, p
, sizeof(str
)-1 - (p
- str
));
854 if ((p
- cfg
->environmt
) + strlen(str
) + 2 <
855 sizeof(cfg
->environmt
)) {
857 p
[strlen(str
) + 1] = '\0';
858 dlg_listbox_add(ed
->listbox
, dlg
, str
);
859 dlg_editbox_set(ed
->varbox
, dlg
, "");
860 dlg_editbox_set(ed
->valbox
, dlg
, "");
862 dlg_error_msg(dlg
, "Environment too big");
864 } else if (ctrl
== ed
->rembutton
) {
865 int i
= dlg_listbox_index(ed
->listbox
, dlg
);
871 dlg_listbox_del(ed
->listbox
, dlg
, i
);
899 struct portfwd_data
{
900 union control
*addbutton
, *rembutton
, *listbox
;
901 union control
*sourcebox
, *destbox
, *direction
;
903 union control
*addressfamily
;
907 static void portfwd_handler(union control
*ctrl
, void *dlg
,
908 void *data
, int event
)
910 Config
*cfg
= (Config
*)data
;
911 struct portfwd_data
*pfd
=
912 (struct portfwd_data
*)ctrl
->generic
.context
.p
;
914 if (event
== EVENT_REFRESH
) {
915 if (ctrl
== pfd
->listbox
) {
916 char *p
= cfg
->portfwd
;
917 dlg_update_start(ctrl
, dlg
);
918 dlg_listbox_clear(ctrl
, dlg
);
920 dlg_listbox_add(ctrl
, dlg
, p
);
923 dlg_update_done(ctrl
, dlg
);
924 } else if (ctrl
== pfd
->direction
) {
928 dlg_radiobutton_set(ctrl
, dlg
, 0);
930 } else if (ctrl
== pfd
->addressfamily
) {
931 dlg_radiobutton_set(ctrl
, dlg
, 0);
934 } else if (event
== EVENT_ACTION
) {
935 if (ctrl
== pfd
->addbutton
) {
936 char str
[sizeof(cfg
->portfwd
)];
943 whichbutton
= dlg_radiobutton_get(pfd
->addressfamily
, dlg
);
944 if (whichbutton
== 1)
946 else if (whichbutton
== 2)
950 whichbutton
= dlg_radiobutton_get(pfd
->direction
, dlg
);
951 if (whichbutton
== 0)
953 else if (whichbutton
== 1)
959 dlg_editbox_get(pfd
->sourcebox
, dlg
, str
+i
, sizeof(str
) - i
);
961 dlg_error_msg(dlg
, "You need to specify a source port number");
964 p
= str
+ strlen(str
);
967 dlg_editbox_get(pfd
->destbox
, dlg
, p
,
968 sizeof(str
) - (p
- str
));
969 if (!*p
|| !strchr(p
, ':')) {
971 "You need to specify a destination address\n"
972 "in the form \"host.name:port\"");
983 if ((p
- cfg
->portfwd
) + strlen(str
) + 2 <=
984 sizeof(cfg
->portfwd
)) {
986 p
[strlen(str
) + 1] = '\0';
987 dlg_listbox_add(pfd
->listbox
, dlg
, str
);
988 dlg_editbox_set(pfd
->sourcebox
, dlg
, "");
989 dlg_editbox_set(pfd
->destbox
, dlg
, "");
991 dlg_error_msg(dlg
, "Too many forwardings");
993 } else if (ctrl
== pfd
->rembutton
) {
994 int i
= dlg_listbox_index(pfd
->listbox
, dlg
);
1000 dlg_listbox_del(pfd
->listbox
, dlg
, i
);
1028 void setup_config_box(struct controlbox
*b
, int midsession
,
1029 int protocol
, int protcfginfo
)
1031 struct controlset
*s
;
1032 struct sessionsaver_data
*ssd
;
1033 struct charclass_data
*ccd
;
1034 struct colour_data
*cd
;
1035 struct ttymodes_data
*td
;
1036 struct environ_data
*ed
;
1037 struct portfwd_data
*pfd
;
1041 ssd
= (struct sessionsaver_data
*)
1042 ctrl_alloc(b
, sizeof(struct sessionsaver_data
));
1043 memset(ssd
, 0, sizeof(*ssd
));
1044 ssd
->midsession
= midsession
;
1047 * The standard panel that appears at the bottom of all panels:
1048 * Open, Cancel, Apply etc.
1050 s
= ctrl_getset(b
, "", "", "");
1051 ctrl_columns(s
, 5, 20, 20, 20, 20, 20);
1052 ssd
->okbutton
= ctrl_pushbutton(s
,
1053 (midsession ?
"Apply" : "Open"),
1054 (char)(midsession ?
'a' : 'o'),
1056 sessionsaver_handler
, P(ssd
));
1057 ssd
->okbutton
->button
.isdefault
= TRUE
;
1058 ssd
->okbutton
->generic
.column
= 3;
1059 ssd
->cancelbutton
= ctrl_pushbutton(s
, "Cancel", 'c', HELPCTX(no_help
),
1060 sessionsaver_handler
, P(ssd
));
1061 ssd
->cancelbutton
->button
.iscancel
= TRUE
;
1062 ssd
->cancelbutton
->generic
.column
= 4;
1063 /* We carefully don't close the 5-column part, so that platform-
1064 * specific add-ons can put extra buttons alongside Open and Cancel. */
1067 * The Session panel.
1069 str
= dupprintf("Basic options for your %s session", appname
);
1070 ctrl_settitle(b
, "Session", str
);
1074 struct hostport
*hp
= (struct hostport
*)
1075 ctrl_alloc(b
, sizeof(struct hostport
));
1077 s
= ctrl_getset(b
, "Session", "hostport",
1078 "Specify the destination you want to connect to");
1079 ctrl_columns(s
, 2, 75, 25);
1080 c
= ctrl_editbox(s
, HOST_BOX_TITLE
, 'n', 100,
1081 HELPCTX(session_hostname
),
1082 config_host_handler
, I(0), I(0));
1083 c
->generic
.column
= 0;
1085 c
= ctrl_editbox(s
, PORT_BOX_TITLE
, 'p', 100,
1086 HELPCTX(session_hostname
),
1087 config_port_handler
, I(0), I(0));
1088 c
->generic
.column
= 1;
1090 ctrl_columns(s
, 1, 100);
1092 if (!have_backend(PROT_SSH
)) {
1093 ctrl_radiobuttons(s
, "Connection type:", NO_SHORTCUT
, 3,
1094 HELPCTX(session_hostname
),
1095 config_protocolbuttons_handler
, P(hp
),
1096 "Raw", 'r', I(PROT_RAW
),
1097 "Telnet", 't', I(PROT_TELNET
),
1098 "Rlogin", 'i', I(PROT_RLOGIN
),
1101 ctrl_radiobuttons(s
, "Connection type:", NO_SHORTCUT
, 4,
1102 HELPCTX(session_hostname
),
1103 config_protocolbuttons_handler
, P(hp
),
1104 "Raw", 'r', I(PROT_RAW
),
1105 "Telnet", 't', I(PROT_TELNET
),
1106 "Rlogin", 'i', I(PROT_RLOGIN
),
1107 "SSH", 's', I(PROT_SSH
),
1113 * The Load/Save panel is available even in mid-session.
1115 s
= ctrl_getset(b
, "Session", "savedsessions",
1116 midsession ?
"Save the current session settings" :
1117 "Load, save or delete a stored session");
1118 ctrl_columns(s
, 2, 75, 25);
1119 get_sesslist(&ssd
->sesslist
, TRUE
);
1120 ssd
->editbox
= ctrl_editbox(s
, "Saved Sessions", 'e', 100,
1121 HELPCTX(session_saved
),
1122 sessionsaver_handler
, P(ssd
), P(NULL
));
1123 ssd
->editbox
->generic
.column
= 0;
1124 /* Reset columns so that the buttons are alongside the list, rather
1125 * than alongside that edit box. */
1126 ctrl_columns(s
, 1, 100);
1127 ctrl_columns(s
, 2, 75, 25);
1128 ssd
->listbox
= ctrl_listbox(s
, NULL
, NO_SHORTCUT
,
1129 HELPCTX(session_saved
),
1130 sessionsaver_handler
, P(ssd
));
1131 ssd
->listbox
->generic
.column
= 0;
1132 ssd
->listbox
->listbox
.height
= 7;
1134 ssd
->loadbutton
= ctrl_pushbutton(s
, "Load", 'l',
1135 HELPCTX(session_saved
),
1136 sessionsaver_handler
, P(ssd
));
1137 ssd
->loadbutton
->generic
.column
= 1;
1139 /* We can't offer the Load button mid-session, as it would allow the
1140 * user to load and subsequently save settings they can't see. (And
1141 * also change otherwise immutable settings underfoot; that probably
1142 * shouldn't be a problem, but.) */
1143 ssd
->loadbutton
= NULL
;
1145 /* "Save" button is permitted mid-session. */
1146 ssd
->savebutton
= ctrl_pushbutton(s
, "Save", 'v',
1147 HELPCTX(session_saved
),
1148 sessionsaver_handler
, P(ssd
));
1149 ssd
->savebutton
->generic
.column
= 1;
1151 ssd
->delbutton
= ctrl_pushbutton(s
, "Delete", 'd',
1152 HELPCTX(session_saved
),
1153 sessionsaver_handler
, P(ssd
));
1154 ssd
->delbutton
->generic
.column
= 1;
1156 /* Disable the Delete button mid-session too, for UI consistency. */
1157 ssd
->delbutton
= NULL
;
1159 ctrl_columns(s
, 1, 100);
1161 s
= ctrl_getset(b
, "Session", "otheropts", NULL
);
1162 c
= ctrl_radiobuttons(s
, "Close window on exit:", 'w', 4,
1163 HELPCTX(session_coe
),
1164 dlg_stdradiobutton_handler
,
1165 I(offsetof(Config
, close_on_exit
)),
1166 "Always", I(FORCE_ON
),
1167 "Never", I(FORCE_OFF
),
1168 "Only on clean exit", I(AUTO
), NULL
);
1171 * The Session/Logging panel.
1173 ctrl_settitle(b
, "Session/Logging", "Options controlling session logging");
1175 s
= ctrl_getset(b
, "Session/Logging", "main", NULL
);
1177 * The logging buttons change depending on whether SSH packet
1178 * logging can sensibly be available.
1181 char *sshlogname
, *sshrawlogname
;
1182 if ((midsession
&& protocol
== PROT_SSH
) ||
1183 (!midsession
&& have_backend(PROT_SSH
))) {
1184 sshlogname
= "SSH packets";
1185 sshrawlogname
= "SSH packets and raw data";
1187 sshlogname
= NULL
; /* this will disable both buttons */
1188 sshrawlogname
= NULL
; /* this will just placate optimisers */
1190 ctrl_radiobuttons(s
, "Session logging:", NO_SHORTCUT
, 2,
1191 HELPCTX(logging_main
),
1192 loggingbuttons_handler
,
1193 I(offsetof(Config
, logtype
)),
1194 "None", 't', I(LGTYP_NONE
),
1195 "Printable output", 'p', I(LGTYP_ASCII
),
1196 "All session output", 'l', I(LGTYP_DEBUG
),
1197 sshlogname
, 's', I(LGTYP_PACKETS
),
1198 sshrawlogname
, 'r', I(LGTYP_SSHRAW
),
1201 ctrl_filesel(s
, "Log file name:", 'f',
1202 NULL
, TRUE
, "Select session log file name",
1203 HELPCTX(logging_filename
),
1204 dlg_stdfilesel_handler
, I(offsetof(Config
, logfilename
)));
1205 ctrl_text(s
, "(Log file name can contain &Y, &M, &D for date,"
1206 " &T for time, and &H for host name)",
1207 HELPCTX(logging_filename
));
1208 ctrl_radiobuttons(s
, "What to do if the log file already exists:", 'e', 1,
1209 HELPCTX(logging_exists
),
1210 dlg_stdradiobutton_handler
, I(offsetof(Config
,logxfovr
)),
1211 "Always overwrite it", I(LGXF_OVR
),
1212 "Always append to the end of it", I(LGXF_APN
),
1213 "Ask the user every time", I(LGXF_ASK
), NULL
);
1214 ctrl_checkbox(s
, "Flush log file frequently", 'u',
1215 HELPCTX(logging_flush
),
1216 dlg_stdcheckbox_handler
, I(offsetof(Config
,logflush
)));
1218 if ((midsession
&& protocol
== PROT_SSH
) ||
1219 (!midsession
&& have_backend(PROT_SSH
))) {
1220 s
= ctrl_getset(b
, "Session/Logging", "ssh",
1221 "Options specific to SSH packet logging");
1222 ctrl_checkbox(s
, "Omit known password fields", 'k',
1223 HELPCTX(logging_ssh_omit_password
),
1224 dlg_stdcheckbox_handler
, I(offsetof(Config
,logomitpass
)));
1225 ctrl_checkbox(s
, "Omit session data", 'd',
1226 HELPCTX(logging_ssh_omit_data
),
1227 dlg_stdcheckbox_handler
, I(offsetof(Config
,logomitdata
)));
1231 * The Terminal panel.
1233 ctrl_settitle(b
, "Terminal", "Options controlling the terminal emulation");
1235 s
= ctrl_getset(b
, "Terminal", "general", "Set various terminal options");
1236 ctrl_checkbox(s
, "Auto wrap mode initially on", 'w',
1237 HELPCTX(terminal_autowrap
),
1238 dlg_stdcheckbox_handler
, I(offsetof(Config
,wrap_mode
)));
1239 ctrl_checkbox(s
, "DEC Origin Mode initially on", 'd',
1240 HELPCTX(terminal_decom
),
1241 dlg_stdcheckbox_handler
, I(offsetof(Config
,dec_om
)));
1242 ctrl_checkbox(s
, "Implicit CR in every LF", 'r',
1243 HELPCTX(terminal_lfhascr
),
1244 dlg_stdcheckbox_handler
, I(offsetof(Config
,lfhascr
)));
1245 ctrl_checkbox(s
, "Use background colour to erase screen", 'e',
1246 HELPCTX(terminal_bce
),
1247 dlg_stdcheckbox_handler
, I(offsetof(Config
,bce
)));
1248 ctrl_checkbox(s
, "Enable blinking text", 'n',
1249 HELPCTX(terminal_blink
),
1250 dlg_stdcheckbox_handler
, I(offsetof(Config
,blinktext
)));
1251 ctrl_editbox(s
, "Answerback to ^E:", 's', 100,
1252 HELPCTX(terminal_answerback
),
1253 dlg_stdeditbox_handler
, I(offsetof(Config
,answerback
)),
1254 I(sizeof(((Config
*)0)->answerback
)));
1256 s
= ctrl_getset(b
, "Terminal", "ldisc", "Line discipline options");
1257 ctrl_radiobuttons(s
, "Local echo:", 'l', 3,
1258 HELPCTX(terminal_localecho
),
1259 dlg_stdradiobutton_handler
,I(offsetof(Config
,localecho
)),
1261 "Force on", I(FORCE_ON
),
1262 "Force off", I(FORCE_OFF
), NULL
);
1263 ctrl_radiobuttons(s
, "Local line editing:", 't', 3,
1264 HELPCTX(terminal_localedit
),
1265 dlg_stdradiobutton_handler
,I(offsetof(Config
,localedit
)),
1267 "Force on", I(FORCE_ON
),
1268 "Force off", I(FORCE_OFF
), NULL
);
1270 s
= ctrl_getset(b
, "Terminal", "printing", "Remote-controlled printing");
1271 ctrl_combobox(s
, "Printer to send ANSI printer output to:", 'p', 100,
1272 HELPCTX(terminal_printing
),
1273 printerbox_handler
, P(NULL
), P(NULL
));
1276 * The Terminal/Keyboard panel.
1278 ctrl_settitle(b
, "Terminal/Keyboard",
1279 "Options controlling the effects of keys");
1281 s
= ctrl_getset(b
, "Terminal/Keyboard", "mappings",
1282 "Change the sequences sent by:");
1283 ctrl_radiobuttons(s
, "The Backspace key", 'b', 2,
1284 HELPCTX(keyboard_backspace
),
1285 dlg_stdradiobutton_handler
,
1286 I(offsetof(Config
, bksp_is_delete
)),
1287 "Control-H", I(0), "Control-? (127)", I(1), NULL
);
1288 ctrl_radiobuttons(s
, "The Home and End keys", 'e', 2,
1289 HELPCTX(keyboard_homeend
),
1290 dlg_stdradiobutton_handler
,
1291 I(offsetof(Config
, rxvt_homeend
)),
1292 "Standard", I(0), "rxvt", I(1), NULL
);
1293 ctrl_radiobuttons(s
, "The Function keys and keypad", 'f', 3,
1294 HELPCTX(keyboard_funkeys
),
1295 dlg_stdradiobutton_handler
,
1296 I(offsetof(Config
, funky_type
)),
1297 "ESC[n~", I(0), "Linux", I(1), "Xterm R6", I(2),
1298 "VT400", I(3), "VT100+", I(4), "SCO", I(5), NULL
);
1300 s
= ctrl_getset(b
, "Terminal/Keyboard", "appkeypad",
1301 "Application keypad settings:");
1302 ctrl_radiobuttons(s
, "Initial state of cursor keys:", 'r', 3,
1303 HELPCTX(keyboard_appcursor
),
1304 dlg_stdradiobutton_handler
,
1305 I(offsetof(Config
, app_cursor
)),
1306 "Normal", I(0), "Application", I(1), NULL
);
1307 ctrl_radiobuttons(s
, "Initial state of numeric keypad:", 'n', 3,
1308 HELPCTX(keyboard_appkeypad
),
1309 numeric_keypad_handler
, P(NULL
),
1310 "Normal", I(0), "Application", I(1), "NetHack", I(2),
1314 * The Terminal/Bell panel.
1316 ctrl_settitle(b
, "Terminal/Bell",
1317 "Options controlling the terminal bell");
1319 s
= ctrl_getset(b
, "Terminal/Bell", "style", "Set the style of bell");
1320 ctrl_radiobuttons(s
, "Action to happen when a bell occurs:", 'b', 1,
1321 HELPCTX(bell_style
),
1322 dlg_stdradiobutton_handler
, I(offsetof(Config
, beep
)),
1323 "None (bell disabled)", I(BELL_DISABLED
),
1324 "Make default system alert sound", I(BELL_DEFAULT
),
1325 "Visual bell (flash window)", I(BELL_VISUAL
), NULL
);
1327 s
= ctrl_getset(b
, "Terminal/Bell", "overload",
1328 "Control the bell overload behaviour");
1329 ctrl_checkbox(s
, "Bell is temporarily disabled when over-used", 'd',
1330 HELPCTX(bell_overload
),
1331 dlg_stdcheckbox_handler
, I(offsetof(Config
,bellovl
)));
1332 ctrl_editbox(s
, "Over-use means this many bells...", 'm', 20,
1333 HELPCTX(bell_overload
),
1334 dlg_stdeditbox_handler
, I(offsetof(Config
,bellovl_n
)), I(-1));
1335 ctrl_editbox(s
, "... in this many seconds", 't', 20,
1336 HELPCTX(bell_overload
),
1337 dlg_stdeditbox_handler
, I(offsetof(Config
,bellovl_t
)),
1339 ctrl_text(s
, "The bell is re-enabled after a few seconds of silence.",
1340 HELPCTX(bell_overload
));
1341 ctrl_editbox(s
, "Seconds of silence required", 's', 20,
1342 HELPCTX(bell_overload
),
1343 dlg_stdeditbox_handler
, I(offsetof(Config
,bellovl_s
)),
1347 * The Terminal/Features panel.
1349 ctrl_settitle(b
, "Terminal/Features",
1350 "Enabling and disabling advanced terminal features");
1352 s
= ctrl_getset(b
, "Terminal/Features", "main", NULL
);
1353 ctrl_checkbox(s
, "Disable application cursor keys mode", 'u',
1354 HELPCTX(features_application
),
1355 dlg_stdcheckbox_handler
, I(offsetof(Config
,no_applic_c
)));
1356 ctrl_checkbox(s
, "Disable application keypad mode", 'k',
1357 HELPCTX(features_application
),
1358 dlg_stdcheckbox_handler
, I(offsetof(Config
,no_applic_k
)));
1359 ctrl_checkbox(s
, "Disable xterm-style mouse reporting", 'x',
1360 HELPCTX(features_mouse
),
1361 dlg_stdcheckbox_handler
, I(offsetof(Config
,no_mouse_rep
)));
1362 ctrl_checkbox(s
, "Disable remote-controlled terminal resizing", 's',
1363 HELPCTX(features_resize
),
1364 dlg_stdcheckbox_handler
,
1365 I(offsetof(Config
,no_remote_resize
)));
1366 ctrl_checkbox(s
, "Disable switching to alternate terminal screen", 'w',
1367 HELPCTX(features_altscreen
),
1368 dlg_stdcheckbox_handler
, I(offsetof(Config
,no_alt_screen
)));
1369 ctrl_checkbox(s
, "Disable remote-controlled window title changing", 't',
1370 HELPCTX(features_retitle
),
1371 dlg_stdcheckbox_handler
,
1372 I(offsetof(Config
,no_remote_wintitle
)));
1373 ctrl_radiobuttons(s
, "Response to remote title query (SECURITY):", 'q', 3,
1374 HELPCTX(features_qtitle
),
1375 dlg_stdradiobutton_handler
,
1376 I(offsetof(Config
,remote_qtitle_action
)),
1377 "None", I(TITLE_NONE
),
1378 "Empty string", I(TITLE_EMPTY
),
1379 "Window title", I(TITLE_REAL
), NULL
);
1380 ctrl_checkbox(s
, "Disable destructive backspace on server sending ^?",'b',
1381 HELPCTX(features_dbackspace
),
1382 dlg_stdcheckbox_handler
, I(offsetof(Config
,no_dbackspace
)));
1383 ctrl_checkbox(s
, "Disable remote-controlled character set configuration",
1384 'r', HELPCTX(features_charset
), dlg_stdcheckbox_handler
,
1385 I(offsetof(Config
,no_remote_charset
)));
1386 ctrl_checkbox(s
, "Disable Arabic text shaping",
1387 'l', HELPCTX(features_arabicshaping
), dlg_stdcheckbox_handler
,
1388 I(offsetof(Config
, arabicshaping
)));
1389 ctrl_checkbox(s
, "Disable bidirectional text display",
1390 'd', HELPCTX(features_bidi
), dlg_stdcheckbox_handler
,
1391 I(offsetof(Config
, bidi
)));
1396 str
= dupprintf("Options controlling %s's window", appname
);
1397 ctrl_settitle(b
, "Window", str
);
1400 s
= ctrl_getset(b
, "Window", "size", "Set the size of the window");
1401 ctrl_columns(s
, 2, 50, 50);
1402 c
= ctrl_editbox(s
, "Rows", 'r', 100,
1403 HELPCTX(window_size
),
1404 dlg_stdeditbox_handler
, I(offsetof(Config
,height
)),I(-1));
1405 c
->generic
.column
= 0;
1406 c
= ctrl_editbox(s
, "Columns", 'm', 100,
1407 HELPCTX(window_size
),
1408 dlg_stdeditbox_handler
, I(offsetof(Config
,width
)), I(-1));
1409 c
->generic
.column
= 1;
1410 ctrl_columns(s
, 1, 100);
1412 s
= ctrl_getset(b
, "Window", "scrollback",
1413 "Control the scrollback in the window");
1414 ctrl_editbox(s
, "Lines of scrollback", 's', 50,
1415 HELPCTX(window_scrollback
),
1416 dlg_stdeditbox_handler
, I(offsetof(Config
,savelines
)), I(-1));
1417 ctrl_checkbox(s
, "Display scrollbar", 'd',
1418 HELPCTX(window_scrollback
),
1419 dlg_stdcheckbox_handler
, I(offsetof(Config
,scrollbar
)));
1420 ctrl_checkbox(s
, "Reset scrollback on keypress", 'k',
1421 HELPCTX(window_scrollback
),
1422 dlg_stdcheckbox_handler
, I(offsetof(Config
,scroll_on_key
)));
1423 ctrl_checkbox(s
, "Reset scrollback on display activity", 'p',
1424 HELPCTX(window_scrollback
),
1425 dlg_stdcheckbox_handler
, I(offsetof(Config
,scroll_on_disp
)));
1426 ctrl_checkbox(s
, "Push erased text into scrollback", 'e',
1427 HELPCTX(window_erased
),
1428 dlg_stdcheckbox_handler
,
1429 I(offsetof(Config
,erase_to_scrollback
)));
1432 * The Window/Appearance panel.
1434 str
= dupprintf("Configure the appearance of %s's window", appname
);
1435 ctrl_settitle(b
, "Window/Appearance", str
);
1438 s
= ctrl_getset(b
, "Window/Appearance", "cursor",
1439 "Adjust the use of the cursor");
1440 ctrl_radiobuttons(s
, "Cursor appearance:", NO_SHORTCUT
, 3,
1441 HELPCTX(appearance_cursor
),
1442 dlg_stdradiobutton_handler
,
1443 I(offsetof(Config
, cursor_type
)),
1445 "Underline", 'u', I(1),
1446 "Vertical line", 'v', I(2), NULL
);
1447 ctrl_checkbox(s
, "Cursor blinks", 'b',
1448 HELPCTX(appearance_cursor
),
1449 dlg_stdcheckbox_handler
, I(offsetof(Config
,blink_cur
)));
1451 s
= ctrl_getset(b
, "Window/Appearance", "font",
1453 ctrl_fontsel(s
, "Font used in the terminal window", 'n',
1454 HELPCTX(appearance_font
),
1455 dlg_stdfontsel_handler
, I(offsetof(Config
, font
)));
1457 s
= ctrl_getset(b
, "Window/Appearance", "mouse",
1458 "Adjust the use of the mouse pointer");
1459 ctrl_checkbox(s
, "Hide mouse pointer when typing in window", 'p',
1460 HELPCTX(appearance_hidemouse
),
1461 dlg_stdcheckbox_handler
, I(offsetof(Config
,hide_mouseptr
)));
1463 s
= ctrl_getset(b
, "Window/Appearance", "border",
1464 "Adjust the window border");
1465 ctrl_editbox(s
, "Gap between text and window edge:", 'e', 20,
1466 HELPCTX(appearance_border
),
1467 dlg_stdeditbox_handler
,
1468 I(offsetof(Config
,window_border
)), I(-1));
1471 * The Window/Behaviour panel.
1473 str
= dupprintf("Configure the behaviour of %s's window", appname
);
1474 ctrl_settitle(b
, "Window/Behaviour", str
);
1477 s
= ctrl_getset(b
, "Window/Behaviour", "title",
1478 "Adjust the behaviour of the window title");
1479 ctrl_editbox(s
, "Window title:", 't', 100,
1480 HELPCTX(appearance_title
),
1481 dlg_stdeditbox_handler
, I(offsetof(Config
,wintitle
)),
1482 I(sizeof(((Config
*)0)->wintitle
)));
1483 ctrl_checkbox(s
, "Separate window and icon titles", 'i',
1484 HELPCTX(appearance_title
),
1485 dlg_stdcheckbox_handler
,
1486 I(CHECKBOX_INVERT
| offsetof(Config
,win_name_always
)));
1488 s
= ctrl_getset(b
, "Window/Behaviour", "main", NULL
);
1489 ctrl_checkbox(s
, "Warn before closing window", 'w',
1490 HELPCTX(behaviour_closewarn
),
1491 dlg_stdcheckbox_handler
, I(offsetof(Config
,warn_on_close
)));
1494 * The Window/Translation panel.
1496 ctrl_settitle(b
, "Window/Translation",
1497 "Options controlling character set translation");
1499 s
= ctrl_getset(b
, "Window/Translation", "trans",
1500 "Character set translation on received data");
1501 ctrl_combobox(s
, "Received data assumed to be in which character set:",
1502 'r', 100, HELPCTX(translation_codepage
),
1503 codepage_handler
, P(NULL
), P(NULL
));
1505 s
= ctrl_getset(b
, "Window/Translation", "tweaks", NULL
);
1506 ctrl_checkbox(s
, "Treat CJK ambiguous characters as wide", 'w',
1507 HELPCTX(translation_cjk_ambig_wide
),
1508 dlg_stdcheckbox_handler
, I(offsetof(Config
,cjk_ambig_wide
)));
1510 str
= dupprintf("Adjust how %s handles line drawing characters", appname
);
1511 s
= ctrl_getset(b
, "Window/Translation", "linedraw", str
);
1513 ctrl_radiobuttons(s
, "Handling of line drawing characters:", NO_SHORTCUT
,1,
1514 HELPCTX(translation_linedraw
),
1515 dlg_stdradiobutton_handler
,
1516 I(offsetof(Config
, vtmode
)),
1517 "Use Unicode line drawing code points",'u',I(VT_UNICODE
),
1518 "Poor man's line drawing (+, - and |)",'p',I(VT_POORMAN
),
1520 ctrl_checkbox(s
, "Copy and paste line drawing characters as lqqqk",'d',
1521 HELPCTX(selection_linedraw
),
1522 dlg_stdcheckbox_handler
, I(offsetof(Config
,rawcnp
)));
1525 * The Window/Selection panel.
1527 ctrl_settitle(b
, "Window/Selection", "Options controlling copy and paste");
1529 s
= ctrl_getset(b
, "Window/Selection", "mouse",
1530 "Control use of mouse");
1531 ctrl_checkbox(s
, "Shift overrides application's use of mouse", 'p',
1532 HELPCTX(selection_shiftdrag
),
1533 dlg_stdcheckbox_handler
, I(offsetof(Config
,mouse_override
)));
1534 ctrl_radiobuttons(s
,
1535 "Default selection mode (Alt+drag does the other one):",
1537 HELPCTX(selection_rect
),
1538 dlg_stdradiobutton_handler
,
1539 I(offsetof(Config
, rect_select
)),
1540 "Normal", 'n', I(0),
1541 "Rectangular block", 'r', I(1), NULL
);
1543 s
= ctrl_getset(b
, "Window/Selection", "charclass",
1544 "Control the select-one-word-at-a-time mode");
1545 ccd
= (struct charclass_data
*)
1546 ctrl_alloc(b
, sizeof(struct charclass_data
));
1547 ccd
->listbox
= ctrl_listbox(s
, "Character classes:", 'e',
1548 HELPCTX(selection_charclasses
),
1549 charclass_handler
, P(ccd
));
1550 ccd
->listbox
->listbox
.multisel
= 1;
1551 ccd
->listbox
->listbox
.ncols
= 4;
1552 ccd
->listbox
->listbox
.percentages
= snewn(4, int);
1553 ccd
->listbox
->listbox
.percentages
[0] = 15;
1554 ccd
->listbox
->listbox
.percentages
[1] = 25;
1555 ccd
->listbox
->listbox
.percentages
[2] = 20;
1556 ccd
->listbox
->listbox
.percentages
[3] = 40;
1557 ctrl_columns(s
, 2, 67, 33);
1558 ccd
->editbox
= ctrl_editbox(s
, "Set to class", 't', 50,
1559 HELPCTX(selection_charclasses
),
1560 charclass_handler
, P(ccd
), P(NULL
));
1561 ccd
->editbox
->generic
.column
= 0;
1562 ccd
->button
= ctrl_pushbutton(s
, "Set", 's',
1563 HELPCTX(selection_charclasses
),
1564 charclass_handler
, P(ccd
));
1565 ccd
->button
->generic
.column
= 1;
1566 ctrl_columns(s
, 1, 100);
1569 * The Window/Colours panel.
1571 ctrl_settitle(b
, "Window/Colours", "Options controlling use of colours");
1573 s
= ctrl_getset(b
, "Window/Colours", "general",
1574 "General options for colour usage");
1575 ctrl_checkbox(s
, "Allow terminal to specify ANSI colours", 'i',
1576 HELPCTX(colours_ansi
),
1577 dlg_stdcheckbox_handler
, I(offsetof(Config
,ansi_colour
)));
1578 ctrl_checkbox(s
, "Allow terminal to use xterm 256-colour mode", '2',
1579 HELPCTX(colours_xterm256
), dlg_stdcheckbox_handler
,
1580 I(offsetof(Config
,xterm_256_colour
)));
1581 ctrl_checkbox(s
, "Bolded text is a different colour", 'b',
1582 HELPCTX(colours_bold
),
1583 dlg_stdcheckbox_handler
, I(offsetof(Config
,bold_colour
)));
1585 str
= dupprintf("Adjust the precise colours %s displays", appname
);
1586 s
= ctrl_getset(b
, "Window/Colours", "adjust", str
);
1588 ctrl_text(s
, "Select a colour from the list, and then click the"
1589 " Modify button to change its appearance.",
1590 HELPCTX(colours_config
));
1591 ctrl_columns(s
, 2, 67, 33);
1592 cd
= (struct colour_data
*)ctrl_alloc(b
, sizeof(struct colour_data
));
1593 cd
->listbox
= ctrl_listbox(s
, "Select a colour to adjust:", 'u',
1594 HELPCTX(colours_config
), colour_handler
, P(cd
));
1595 cd
->listbox
->generic
.column
= 0;
1596 cd
->listbox
->listbox
.height
= 7;
1597 c
= ctrl_text(s
, "RGB value:", HELPCTX(colours_config
));
1598 c
->generic
.column
= 1;
1599 cd
->redit
= ctrl_editbox(s
, "Red", 'r', 50, HELPCTX(colours_config
),
1600 colour_handler
, P(cd
), P(NULL
));
1601 cd
->redit
->generic
.column
= 1;
1602 cd
->gedit
= ctrl_editbox(s
, "Green", 'n', 50, HELPCTX(colours_config
),
1603 colour_handler
, P(cd
), P(NULL
));
1604 cd
->gedit
->generic
.column
= 1;
1605 cd
->bedit
= ctrl_editbox(s
, "Blue", 'e', 50, HELPCTX(colours_config
),
1606 colour_handler
, P(cd
), P(NULL
));
1607 cd
->bedit
->generic
.column
= 1;
1608 cd
->button
= ctrl_pushbutton(s
, "Modify", 'm', HELPCTX(colours_config
),
1609 colour_handler
, P(cd
));
1610 cd
->button
->generic
.column
= 1;
1611 ctrl_columns(s
, 1, 100);
1614 * The Connection panel. This doesn't show up if we're in a
1615 * non-network utility such as pterm. We tell this by being
1616 * passed a protocol < 0.
1618 if (protocol
>= 0) {
1619 ctrl_settitle(b
, "Connection", "Options controlling the connection");
1621 s
= ctrl_getset(b
, "Connection", "keepalive",
1622 "Sending of null packets to keep session active");
1623 ctrl_editbox(s
, "Seconds between keepalives (0 to turn off)", 'k', 20,
1624 HELPCTX(connection_keepalive
),
1625 dlg_stdeditbox_handler
, I(offsetof(Config
,ping_interval
)),
1629 s
= ctrl_getset(b
, "Connection", "tcp",
1630 "Low-level TCP connection options");
1631 ctrl_checkbox(s
, "Disable Nagle's algorithm (TCP_NODELAY option)",
1632 'n', HELPCTX(connection_nodelay
),
1633 dlg_stdcheckbox_handler
,
1634 I(offsetof(Config
,tcp_nodelay
)));
1635 ctrl_checkbox(s
, "Enable TCP keepalives (SO_KEEPALIVE option)",
1636 'p', HELPCTX(connection_tcpkeepalive
),
1637 dlg_stdcheckbox_handler
,
1638 I(offsetof(Config
,tcp_keepalives
)));
1640 s
= ctrl_getset(b
, "Connection", "ipversion",
1641 "Internet protocol version");
1642 ctrl_radiobuttons(s
, NULL
, NO_SHORTCUT
, 3,
1643 HELPCTX(connection_ipversion
),
1644 dlg_stdradiobutton_handler
,
1645 I(offsetof(Config
, addressfamily
)),
1646 "Auto", 'u', I(ADDRTYPE_UNSPEC
),
1647 "IPv4", '4', I(ADDRTYPE_IPV4
),
1648 "IPv6", '6', I(ADDRTYPE_IPV6
),
1654 * A sub-panel Connection/Data, containing options that
1655 * decide on data to send to the server.
1658 ctrl_settitle(b
, "Connection/Data", "Data to send to the server");
1660 s
= ctrl_getset(b
, "Connection/Data", "login",
1662 ctrl_editbox(s
, "Auto-login username", 'u', 50,
1663 HELPCTX(connection_username
),
1664 dlg_stdeditbox_handler
, I(offsetof(Config
,username
)),
1665 I(sizeof(((Config
*)0)->username
)));
1667 s
= ctrl_getset(b
, "Connection/Data", "term",
1668 "Terminal details");
1669 ctrl_editbox(s
, "Terminal-type string", 't', 50,
1670 HELPCTX(connection_termtype
),
1671 dlg_stdeditbox_handler
, I(offsetof(Config
,termtype
)),
1672 I(sizeof(((Config
*)0)->termtype
)));
1673 ctrl_editbox(s
, "Terminal speeds", 's', 50,
1674 HELPCTX(connection_termspeed
),
1675 dlg_stdeditbox_handler
, I(offsetof(Config
,termspeed
)),
1676 I(sizeof(((Config
*)0)->termspeed
)));
1678 s
= ctrl_getset(b
, "Connection/Data", "env",
1679 "Environment variables");
1680 ctrl_columns(s
, 2, 80, 20);
1681 ed
= (struct environ_data
*)
1682 ctrl_alloc(b
, sizeof(struct environ_data
));
1683 ed
->varbox
= ctrl_editbox(s
, "Variable", 'v', 60,
1684 HELPCTX(telnet_environ
),
1685 environ_handler
, P(ed
), P(NULL
));
1686 ed
->varbox
->generic
.column
= 0;
1687 ed
->valbox
= ctrl_editbox(s
, "Value", 'l', 60,
1688 HELPCTX(telnet_environ
),
1689 environ_handler
, P(ed
), P(NULL
));
1690 ed
->valbox
->generic
.column
= 0;
1691 ed
->addbutton
= ctrl_pushbutton(s
, "Add", 'd',
1692 HELPCTX(telnet_environ
),
1693 environ_handler
, P(ed
));
1694 ed
->addbutton
->generic
.column
= 1;
1695 ed
->rembutton
= ctrl_pushbutton(s
, "Remove", 'r',
1696 HELPCTX(telnet_environ
),
1697 environ_handler
, P(ed
));
1698 ed
->rembutton
->generic
.column
= 1;
1699 ctrl_columns(s
, 1, 100);
1700 ed
->listbox
= ctrl_listbox(s
, NULL
, NO_SHORTCUT
,
1701 HELPCTX(telnet_environ
),
1702 environ_handler
, P(ed
));
1703 ed
->listbox
->listbox
.height
= 3;
1704 ed
->listbox
->listbox
.ncols
= 2;
1705 ed
->listbox
->listbox
.percentages
= snewn(2, int);
1706 ed
->listbox
->listbox
.percentages
[0] = 30;
1707 ed
->listbox
->listbox
.percentages
[1] = 70;
1714 * The Connection/Proxy panel.
1716 ctrl_settitle(b
, "Connection/Proxy",
1717 "Options controlling proxy usage");
1719 s
= ctrl_getset(b
, "Connection/Proxy", "basics", NULL
);
1720 ctrl_radiobuttons(s
, "Proxy type:", 't', 3,
1721 HELPCTX(proxy_type
),
1722 dlg_stdradiobutton_handler
,
1723 I(offsetof(Config
, proxy_type
)),
1724 "None", I(PROXY_NONE
),
1725 "SOCKS 4", I(PROXY_SOCKS4
),
1726 "SOCKS 5", I(PROXY_SOCKS5
),
1727 "HTTP", I(PROXY_HTTP
),
1728 "Telnet", I(PROXY_TELNET
),
1730 ctrl_columns(s
, 2, 80, 20);
1731 c
= ctrl_editbox(s
, "Proxy hostname", 'y', 100,
1732 HELPCTX(proxy_main
),
1733 dlg_stdeditbox_handler
,
1734 I(offsetof(Config
,proxy_host
)),
1735 I(sizeof(((Config
*)0)->proxy_host
)));
1736 c
->generic
.column
= 0;
1737 c
= ctrl_editbox(s
, "Port", 'p', 100,
1738 HELPCTX(proxy_main
),
1739 dlg_stdeditbox_handler
,
1740 I(offsetof(Config
,proxy_port
)),
1742 c
->generic
.column
= 1;
1743 ctrl_columns(s
, 1, 100);
1744 ctrl_editbox(s
, "Exclude Hosts/IPs", 'e', 100,
1745 HELPCTX(proxy_exclude
),
1746 dlg_stdeditbox_handler
,
1747 I(offsetof(Config
,proxy_exclude_list
)),
1748 I(sizeof(((Config
*)0)->proxy_exclude_list
)));
1749 ctrl_checkbox(s
, "Consider proxying local host connections", 'x',
1750 HELPCTX(proxy_exclude
),
1751 dlg_stdcheckbox_handler
,
1752 I(offsetof(Config
,even_proxy_localhost
)));
1753 ctrl_radiobuttons(s
, "Do DNS name lookup at proxy end:", 'd', 3,
1755 dlg_stdradiobutton_handler
,
1756 I(offsetof(Config
, proxy_dns
)),
1759 "Yes", I(FORCE_ON
), NULL
);
1760 ctrl_editbox(s
, "Username", 'u', 60,
1761 HELPCTX(proxy_auth
),
1762 dlg_stdeditbox_handler
,
1763 I(offsetof(Config
,proxy_username
)),
1764 I(sizeof(((Config
*)0)->proxy_username
)));
1765 c
= ctrl_editbox(s
, "Password", 'w', 60,
1766 HELPCTX(proxy_auth
),
1767 dlg_stdeditbox_handler
,
1768 I(offsetof(Config
,proxy_password
)),
1769 I(sizeof(((Config
*)0)->proxy_password
)));
1770 c
->editbox
.password
= 1;
1771 ctrl_editbox(s
, "Telnet command", 'm', 100,
1772 HELPCTX(proxy_command
),
1773 dlg_stdeditbox_handler
,
1774 I(offsetof(Config
,proxy_telnet_command
)),
1775 I(sizeof(((Config
*)0)->proxy_telnet_command
)));
1779 * The Telnet panel exists in the base config box, and in a
1780 * mid-session reconfig box _if_ we're using Telnet.
1782 if (!midsession
|| protocol
== PROT_TELNET
) {
1784 * The Connection/Telnet panel.
1786 ctrl_settitle(b
, "Connection/Telnet",
1787 "Options controlling Telnet connections");
1789 s
= ctrl_getset(b
, "Connection/Telnet", "protocol",
1790 "Telnet protocol adjustments");
1793 ctrl_radiobuttons(s
, "Handling of OLD_ENVIRON ambiguity:",
1795 HELPCTX(telnet_oldenviron
),
1796 dlg_stdradiobutton_handler
,
1797 I(offsetof(Config
, rfc_environ
)),
1798 "BSD (commonplace)", 'b', I(0),
1799 "RFC 1408 (unusual)", 'f', I(1), NULL
);
1800 ctrl_radiobuttons(s
, "Telnet negotiation mode:", 't', 2,
1801 HELPCTX(telnet_passive
),
1802 dlg_stdradiobutton_handler
,
1803 I(offsetof(Config
, passive_telnet
)),
1804 "Passive", I(1), "Active", I(0), NULL
);
1806 ctrl_checkbox(s
, "Keyboard sends Telnet special commands", 'k',
1807 HELPCTX(telnet_specialkeys
),
1808 dlg_stdcheckbox_handler
,
1809 I(offsetof(Config
,telnet_keyboard
)));
1810 ctrl_checkbox(s
, "Return key sends Telnet New Line instead of ^M",
1811 'm', HELPCTX(telnet_newline
),
1812 dlg_stdcheckbox_handler
,
1813 I(offsetof(Config
,telnet_newline
)));
1819 * The Connection/Rlogin panel.
1821 ctrl_settitle(b
, "Connection/Rlogin",
1822 "Options controlling Rlogin connections");
1824 s
= ctrl_getset(b
, "Connection/Rlogin", "data",
1825 "Data to send to the server");
1826 ctrl_editbox(s
, "Local username:", 'l', 50,
1827 HELPCTX(rlogin_localuser
),
1828 dlg_stdeditbox_handler
, I(offsetof(Config
,localusername
)),
1829 I(sizeof(((Config
*)0)->localusername
)));
1834 * All the SSH stuff is omitted in PuTTYtel, or in a reconfig
1835 * when we're not doing SSH.
1838 if (have_backend(PROT_SSH
) && (!midsession
|| protocol
== PROT_SSH
)) {
1841 * The Connection/SSH panel.
1843 ctrl_settitle(b
, "Connection/SSH",
1844 "Options controlling SSH connections");
1846 if (midsession
&& protcfginfo
== 1) {
1847 s
= ctrl_getset(b
, "Connection/SSH", "disclaimer", NULL
);
1848 ctrl_text(s
, "Nothing on this panel may be reconfigured in mid-"
1849 "session; it is only here so that sub-panels of it can "
1850 "exist without looking strange.", HELPCTX(no_help
));
1855 s
= ctrl_getset(b
, "Connection/SSH", "data",
1856 "Data to send to the server");
1857 ctrl_editbox(s
, "Remote command:", 'r', 100,
1858 HELPCTX(ssh_command
),
1859 dlg_stdeditbox_handler
, I(offsetof(Config
,remote_cmd
)),
1860 I(sizeof(((Config
*)0)->remote_cmd
)));
1862 s
= ctrl_getset(b
, "Connection/SSH", "protocol", "Protocol options");
1863 ctrl_checkbox(s
, "Don't start a shell or command at all", 'n',
1864 HELPCTX(ssh_noshell
),
1865 dlg_stdcheckbox_handler
,
1866 I(offsetof(Config
,ssh_no_shell
)));
1869 if (!midsession
|| protcfginfo
!= 1) {
1870 s
= ctrl_getset(b
, "Connection/SSH", "protocol", "Protocol options");
1872 ctrl_checkbox(s
, "Enable compression", 'e',
1873 HELPCTX(ssh_compress
),
1874 dlg_stdcheckbox_handler
,
1875 I(offsetof(Config
,compression
)));
1879 s
= ctrl_getset(b
, "Connection/SSH", "protocol", "Protocol options");
1881 ctrl_radiobuttons(s
, "Preferred SSH protocol version:", NO_SHORTCUT
, 4,
1882 HELPCTX(ssh_protocol
),
1883 dlg_stdradiobutton_handler
,
1884 I(offsetof(Config
, sshprot
)),
1885 "1 only", 'l', I(0),
1888 "2 only", 'y', I(3), NULL
);
1891 if (!midsession
|| protcfginfo
!= 1) {
1892 s
= ctrl_getset(b
, "Connection/SSH", "encryption", "Encryption options");
1893 c
= ctrl_draglist(s
, "Encryption cipher selection policy:", 's',
1894 HELPCTX(ssh_ciphers
),
1895 cipherlist_handler
, P(NULL
));
1896 c
->listbox
.height
= 6;
1898 ctrl_checkbox(s
, "Enable legacy use of single-DES in SSH-2", 'i',
1899 HELPCTX(ssh_ciphers
),
1900 dlg_stdcheckbox_handler
,
1901 I(offsetof(Config
,ssh2_des_cbc
)));
1905 * The Connection/SSH/Kex panel. (Owing to repeat key
1906 * exchange, this is all meaningful in mid-session _if_
1907 * we're using SSH-2 or haven't decided yet.)
1909 if (protcfginfo
!= 1) {
1910 ctrl_settitle(b
, "Connection/SSH/Kex",
1911 "Options controlling SSH key exchange");
1913 s
= ctrl_getset(b
, "Connection/SSH/Kex", "main",
1914 "Key exchange algorithm options");
1915 c
= ctrl_draglist(s
, "Algorithm selection policy:", 's',
1916 HELPCTX(ssh_kexlist
),
1917 kexlist_handler
, P(NULL
));
1918 c
->listbox
.height
= 5;
1920 s
= ctrl_getset(b
, "Connection/SSH/Kex", "repeat",
1921 "Options controlling key re-exchange");
1923 ctrl_editbox(s
, "Max minutes before rekey (0 for no limit)", 't', 20,
1924 HELPCTX(ssh_kex_repeat
),
1925 dlg_stdeditbox_handler
,
1926 I(offsetof(Config
,ssh_rekey_time
)),
1928 ctrl_editbox(s
, "Max data before rekey (0 for no limit)", 'x', 20,
1929 HELPCTX(ssh_kex_repeat
),
1930 dlg_stdeditbox_handler
,
1931 I(offsetof(Config
,ssh_rekey_data
)),
1933 ctrl_text(s
, "(Use 1M for 1 megabyte, 1G for 1 gigabyte etc)",
1934 HELPCTX(ssh_kex_repeat
));
1940 * The Connection/SSH/Auth panel.
1942 ctrl_settitle(b
, "Connection/SSH/Auth",
1943 "Options controlling SSH authentication");
1945 s
= ctrl_getset(b
, "Connection/SSH/Auth", "main", NULL
);
1946 ctrl_checkbox(s
, "Bypass authentication entirely (SSH-2 only)", 'b',
1947 HELPCTX(ssh_auth_bypass
),
1948 dlg_stdcheckbox_handler
,
1949 I(offsetof(Config
,ssh_no_userauth
)));
1951 s
= ctrl_getset(b
, "Connection/SSH/Auth", "methods",
1952 "Authentication methods");
1953 ctrl_checkbox(s
, "Attempt authentication using Pageant", 'p',
1954 HELPCTX(ssh_auth_pageant
),
1955 dlg_stdcheckbox_handler
,
1956 I(offsetof(Config
,tryagent
)));
1957 ctrl_checkbox(s
, "Attempt TIS or CryptoCard auth (SSH-1)", 'm',
1958 HELPCTX(ssh_auth_tis
),
1959 dlg_stdcheckbox_handler
,
1960 I(offsetof(Config
,try_tis_auth
)));
1961 ctrl_checkbox(s
, "Attempt \"keyboard-interactive\" auth (SSH-2)",
1962 'i', HELPCTX(ssh_auth_ki
),
1963 dlg_stdcheckbox_handler
,
1964 I(offsetof(Config
,try_ki_auth
)));
1966 s
= ctrl_getset(b
, "Connection/SSH/Auth", "params",
1967 "Authentication parameters");
1968 ctrl_checkbox(s
, "Allow agent forwarding", 'f',
1969 HELPCTX(ssh_auth_agentfwd
),
1970 dlg_stdcheckbox_handler
, I(offsetof(Config
,agentfwd
)));
1971 ctrl_checkbox(s
, "Allow attempted changes of username in SSH-2", 'u',
1972 HELPCTX(ssh_auth_changeuser
),
1973 dlg_stdcheckbox_handler
,
1974 I(offsetof(Config
,change_username
)));
1975 ctrl_filesel(s
, "Private key file for authentication:", 'k',
1976 FILTER_KEY_FILES
, FALSE
, "Select private key file",
1977 HELPCTX(ssh_auth_privkey
),
1978 dlg_stdfilesel_handler
, I(offsetof(Config
, keyfile
)));
1983 * The Connection/SSH/TTY panel.
1985 ctrl_settitle(b
, "Connection/SSH/TTY", "Remote terminal settings");
1987 s
= ctrl_getset(b
, "Connection/SSH/TTY", "sshtty", NULL
);
1988 ctrl_checkbox(s
, "Don't allocate a pseudo-terminal", 'p',
1990 dlg_stdcheckbox_handler
,
1991 I(offsetof(Config
,nopty
)));
1993 s
= ctrl_getset(b
, "Connection/SSH/TTY", "ttymodes",
1995 td
= (struct ttymodes_data
*)
1996 ctrl_alloc(b
, sizeof(struct ttymodes_data
));
1997 ctrl_columns(s
, 2, 75, 25);
1998 c
= ctrl_text(s
, "Terminal modes to send:", HELPCTX(ssh_ttymodes
));
1999 c
->generic
.column
= 0;
2000 td
->rembutton
= ctrl_pushbutton(s
, "Remove", 'r',
2001 HELPCTX(ssh_ttymodes
),
2002 ttymodes_handler
, P(td
));
2003 td
->rembutton
->generic
.column
= 1;
2004 td
->rembutton
->generic
.tabdelay
= 1;
2005 ctrl_columns(s
, 1, 100);
2006 td
->listbox
= ctrl_listbox(s
, NULL
, NO_SHORTCUT
,
2007 HELPCTX(ssh_ttymodes
),
2008 ttymodes_handler
, P(td
));
2009 td
->listbox
->listbox
.multisel
= 1;
2010 td
->listbox
->listbox
.height
= 4;
2011 td
->listbox
->listbox
.ncols
= 2;
2012 td
->listbox
->listbox
.percentages
= snewn(2, int);
2013 td
->listbox
->listbox
.percentages
[0] = 40;
2014 td
->listbox
->listbox
.percentages
[1] = 60;
2015 ctrl_tabdelay(s
, td
->rembutton
);
2016 ctrl_columns(s
, 2, 75, 25);
2017 td
->modelist
= ctrl_droplist(s
, "Mode:", 'm', 67,
2018 HELPCTX(ssh_ttymodes
),
2019 ttymodes_handler
, P(td
));
2020 td
->modelist
->generic
.column
= 0;
2021 td
->addbutton
= ctrl_pushbutton(s
, "Add", 'd',
2022 HELPCTX(ssh_ttymodes
),
2023 ttymodes_handler
, P(td
));
2024 td
->addbutton
->generic
.column
= 1;
2025 td
->addbutton
->generic
.tabdelay
= 1;
2026 ctrl_columns(s
, 1, 100); /* column break */
2027 /* Bit of a hack to get the value radio buttons and
2028 * edit-box on the same row. */
2029 ctrl_columns(s
, 3, 25, 50, 25);
2030 c
= ctrl_text(s
, "Value:", HELPCTX(ssh_ttymodes
));
2031 c
->generic
.column
= 0;
2032 td
->valradio
= ctrl_radiobuttons(s
, NULL
, NO_SHORTCUT
, 2,
2033 HELPCTX(ssh_ttymodes
),
2034 ttymodes_handler
, P(td
),
2035 "Auto", NO_SHORTCUT
, P(NULL
),
2036 "This:", NO_SHORTCUT
, P(NULL
),
2038 td
->valradio
->generic
.column
= 1;
2039 td
->valbox
= ctrl_editbox(s
, NULL
, NO_SHORTCUT
, 100,
2040 HELPCTX(ssh_ttymodes
),
2041 ttymodes_handler
, P(td
), P(NULL
));
2042 td
->valbox
->generic
.column
= 2;
2043 ctrl_tabdelay(s
, td
->addbutton
);
2049 * The Connection/SSH/X11 panel.
2051 ctrl_settitle(b
, "Connection/SSH/X11",
2052 "Options controlling SSH X11 forwarding");
2054 s
= ctrl_getset(b
, "Connection/SSH/X11", "x11", "X11 forwarding");
2055 ctrl_checkbox(s
, "Enable X11 forwarding", 'e',
2056 HELPCTX(ssh_tunnels_x11
),
2057 dlg_stdcheckbox_handler
,I(offsetof(Config
,x11_forward
)));
2058 ctrl_editbox(s
, "X display location", 'x', 50,
2059 HELPCTX(ssh_tunnels_x11
),
2060 dlg_stdeditbox_handler
, I(offsetof(Config
,x11_display
)),
2061 I(sizeof(((Config
*)0)->x11_display
)));
2062 ctrl_radiobuttons(s
, "Remote X11 authentication protocol", 'u', 2,
2063 HELPCTX(ssh_tunnels_x11auth
),
2064 dlg_stdradiobutton_handler
,
2065 I(offsetof(Config
, x11_auth
)),
2066 "MIT-Magic-Cookie-1", I(X11_MIT
),
2067 "XDM-Authorization-1", I(X11_XDM
), NULL
);
2071 * The Tunnels panel _is_ still available in mid-session.
2073 ctrl_settitle(b
, "Connection/SSH/Tunnels",
2074 "Options controlling SSH port forwarding");
2076 s
= ctrl_getset(b
, "Connection/SSH/Tunnels", "portfwd",
2078 ctrl_checkbox(s
, "Local ports accept connections from other hosts",'t',
2079 HELPCTX(ssh_tunnels_portfwd_localhost
),
2080 dlg_stdcheckbox_handler
,
2081 I(offsetof(Config
,lport_acceptall
)));
2082 ctrl_checkbox(s
, "Remote ports do the same (SSH-2 only)", 'p',
2083 HELPCTX(ssh_tunnels_portfwd_localhost
),
2084 dlg_stdcheckbox_handler
,
2085 I(offsetof(Config
,rport_acceptall
)));
2087 ctrl_columns(s
, 3, 55, 20, 25);
2088 c
= ctrl_text(s
, "Forwarded ports:", HELPCTX(ssh_tunnels_portfwd
));
2089 c
->generic
.column
= COLUMN_FIELD(0,2);
2090 /* You want to select from the list, _then_ hit Remove. So tab order
2091 * should be that way round. */
2092 pfd
= (struct portfwd_data
*)ctrl_alloc(b
,sizeof(struct portfwd_data
));
2093 pfd
->rembutton
= ctrl_pushbutton(s
, "Remove", 'r',
2094 HELPCTX(ssh_tunnels_portfwd
),
2095 portfwd_handler
, P(pfd
));
2096 pfd
->rembutton
->generic
.column
= 2;
2097 pfd
->rembutton
->generic
.tabdelay
= 1;
2098 pfd
->listbox
= ctrl_listbox(s
, NULL
, NO_SHORTCUT
,
2099 HELPCTX(ssh_tunnels_portfwd
),
2100 portfwd_handler
, P(pfd
));
2101 pfd
->listbox
->listbox
.height
= 3;
2102 pfd
->listbox
->listbox
.ncols
= 2;
2103 pfd
->listbox
->listbox
.percentages
= snewn(2, int);
2104 pfd
->listbox
->listbox
.percentages
[0] = 20;
2105 pfd
->listbox
->listbox
.percentages
[1] = 80;
2106 ctrl_tabdelay(s
, pfd
->rembutton
);
2107 ctrl_text(s
, "Add new forwarded port:", HELPCTX(ssh_tunnels_portfwd
));
2108 /* You want to enter source, destination and type, _then_ hit Add.
2109 * Again, we adjust the tab order to reflect this. */
2110 pfd
->addbutton
= ctrl_pushbutton(s
, "Add", 'd',
2111 HELPCTX(ssh_tunnels_portfwd
),
2112 portfwd_handler
, P(pfd
));
2113 pfd
->addbutton
->generic
.column
= 2;
2114 pfd
->addbutton
->generic
.tabdelay
= 1;
2115 pfd
->sourcebox
= ctrl_editbox(s
, "Source port", 's', 40,
2116 HELPCTX(ssh_tunnels_portfwd
),
2117 portfwd_handler
, P(pfd
), P(NULL
));
2118 pfd
->sourcebox
->generic
.column
= 0;
2119 pfd
->destbox
= ctrl_editbox(s
, "Destination", 'i', 67,
2120 HELPCTX(ssh_tunnels_portfwd
),
2121 portfwd_handler
, P(pfd
), P(NULL
));
2122 pfd
->direction
= ctrl_radiobuttons(s
, NULL
, NO_SHORTCUT
, 3,
2123 HELPCTX(ssh_tunnels_portfwd
),
2124 portfwd_handler
, P(pfd
),
2125 "Local", 'l', P(NULL
),
2126 "Remote", 'm', P(NULL
),
2127 "Dynamic", 'y', P(NULL
),
2130 pfd
->addressfamily
=
2131 ctrl_radiobuttons(s
, NULL
, NO_SHORTCUT
, 3,
2132 HELPCTX(ssh_tunnels_portfwd_ipversion
),
2133 portfwd_handler
, P(pfd
),
2134 "Auto", 'u', I(ADDRTYPE_UNSPEC
),
2135 "IPv4", '4', I(ADDRTYPE_IPV4
),
2136 "IPv6", '6', I(ADDRTYPE_IPV6
),
2139 ctrl_tabdelay(s
, pfd
->addbutton
);
2140 ctrl_columns(s
, 1, 100);
2144 * The Connection/SSH/Bugs panel.
2146 ctrl_settitle(b
, "Connection/SSH/Bugs",
2147 "Workarounds for SSH server bugs");
2149 s
= ctrl_getset(b
, "Connection/SSH/Bugs", "main",
2150 "Detection of known bugs in SSH servers");
2151 ctrl_droplist(s
, "Chokes on SSH-1 ignore messages", 'i', 20,
2152 HELPCTX(ssh_bugs_ignore1
),
2153 sshbug_handler
, I(offsetof(Config
,sshbug_ignore1
)));
2154 ctrl_droplist(s
, "Refuses all SSH-1 password camouflage", 's', 20,
2155 HELPCTX(ssh_bugs_plainpw1
),
2156 sshbug_handler
, I(offsetof(Config
,sshbug_plainpw1
)));
2157 ctrl_droplist(s
, "Chokes on SSH-1 RSA authentication", 'r', 20,
2158 HELPCTX(ssh_bugs_rsa1
),
2159 sshbug_handler
, I(offsetof(Config
,sshbug_rsa1
)));
2160 ctrl_droplist(s
, "Miscomputes SSH-2 HMAC keys", 'm', 20,
2161 HELPCTX(ssh_bugs_hmac2
),
2162 sshbug_handler
, I(offsetof(Config
,sshbug_hmac2
)));
2163 ctrl_droplist(s
, "Miscomputes SSH-2 encryption keys", 'e', 20,
2164 HELPCTX(ssh_bugs_derivekey2
),
2165 sshbug_handler
, I(offsetof(Config
,sshbug_derivekey2
)));
2166 ctrl_droplist(s
, "Requires padding on SSH-2 RSA signatures", 'p', 20,
2167 HELPCTX(ssh_bugs_rsapad2
),
2168 sshbug_handler
, I(offsetof(Config
,sshbug_rsapad2
)));
2169 ctrl_droplist(s
, "Misuses the session ID in SSH-2 PK auth", 'n', 20,
2170 HELPCTX(ssh_bugs_pksessid2
),
2171 sshbug_handler
, I(offsetof(Config
,sshbug_pksessid2
)));
2172 ctrl_droplist(s
, "Handles SSH-2 key re-exchange badly", 'k', 20,
2173 HELPCTX(ssh_bugs_rekey2
),
2174 sshbug_handler
, I(offsetof(Config
,sshbug_rekey2
)));