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 static void config_host_handler(union control
*ctrl
, void *dlg
,
19 void *data
, int event
)
21 Config
*cfg
= (Config
*)data
;
24 * This function works just like the standard edit box handler,
25 * only it has to choose the control's label and text from two
26 * different places depending on the protocol.
28 if (event
== EVENT_REFRESH
) {
29 if (cfg
->protocol
== PROT_SERIAL
) {
31 * This label text is carefully chosen to contain an n,
32 * since that's the shortcut for the host name control.
34 dlg_label_change(ctrl
, dlg
, "Serial line");
35 dlg_editbox_set(ctrl
, dlg
, cfg
->serline
);
37 dlg_label_change(ctrl
, dlg
, HOST_BOX_TITLE
);
38 dlg_editbox_set(ctrl
, dlg
, cfg
->host
);
40 } else if (event
== EVENT_VALCHANGE
) {
41 if (cfg
->protocol
== PROT_SERIAL
)
42 dlg_editbox_get(ctrl
, dlg
, cfg
->serline
, lenof(cfg
->serline
));
44 dlg_editbox_get(ctrl
, dlg
, cfg
->host
, lenof(cfg
->host
));
48 static void config_port_handler(union control
*ctrl
, void *dlg
,
49 void *data
, int event
)
51 Config
*cfg
= (Config
*)data
;
55 * This function works just like the standard edit box handler,
56 * only it has to choose the control's label and text from two
57 * different places depending on the protocol.
59 if (event
== EVENT_REFRESH
) {
60 if (cfg
->protocol
== PROT_SERIAL
) {
62 * This label text is carefully chosen to contain a p,
63 * since that's the shortcut for the port control.
65 dlg_label_change(ctrl
, dlg
, "Speed");
66 sprintf(buf
, "%d", cfg
->serspeed
);
68 dlg_label_change(ctrl
, dlg
, PORT_BOX_TITLE
);
69 sprintf(buf
, "%d", cfg
->port
);
71 dlg_editbox_set(ctrl
, dlg
, buf
);
72 } else if (event
== EVENT_VALCHANGE
) {
73 dlg_editbox_get(ctrl
, dlg
, buf
, lenof(buf
));
74 if (cfg
->protocol
== PROT_SERIAL
)
75 cfg
->serspeed
= atoi(buf
);
77 cfg
->port
= atoi(buf
);
82 union control
*host
, *port
;
86 * We export this function so that platform-specific config
87 * routines can use it to conveniently identify the protocol radio
88 * buttons in order to add to them.
90 void config_protocolbuttons_handler(union control
*ctrl
, void *dlg
,
91 void *data
, int event
)
94 Config
*cfg
= (Config
*)data
;
95 struct hostport
*hp
= (struct hostport
*)ctrl
->radio
.context
.p
;
98 * This function works just like the standard radio-button
99 * handler, except that it also has to change the setting of
100 * the port box, and refresh both host and port boxes when. We
101 * expect the context parameter to point at a hostport
102 * structure giving the `union control's for both.
104 if (event
== EVENT_REFRESH
) {
105 for (button
= 0; button
< ctrl
->radio
.nbuttons
; button
++)
106 if (cfg
->protocol
== ctrl
->radio
.buttondata
[button
].i
)
108 /* We expected that `break' to happen, in all circumstances. */
109 assert(button
< ctrl
->radio
.nbuttons
);
110 dlg_radiobutton_set(ctrl
, dlg
, button
);
111 } else if (event
== EVENT_VALCHANGE
) {
112 int oldproto
= cfg
->protocol
;
113 button
= dlg_radiobutton_get(ctrl
, dlg
);
114 assert(button
>= 0 && button
< ctrl
->radio
.nbuttons
);
115 cfg
->protocol
= ctrl
->radio
.buttondata
[button
].i
;
116 if (oldproto
!= cfg
->protocol
) {
118 switch (cfg
->protocol
) {
119 case PROT_SSH
: defport
= 22; break;
120 case PROT_TELNET
: defport
= 23; break;
121 case PROT_RLOGIN
: defport
= 513; break;
123 if (defport
> 0 && cfg
->port
!= defport
) {
127 dlg_refresh(hp
->host
, dlg
);
128 dlg_refresh(hp
->port
, dlg
);
132 static void loggingbuttons_handler(union control
*ctrl
, void *dlg
,
133 void *data
, int event
)
136 Config
*cfg
= (Config
*)data
;
137 /* This function works just like the standard radio-button handler,
138 * but it has to fall back to "no logging" in situations where the
139 * configured logging type isn't applicable.
141 if (event
== EVENT_REFRESH
) {
142 for (button
= 0; button
< ctrl
->radio
.nbuttons
; button
++)
143 if (cfg
->logtype
== ctrl
->radio
.buttondata
[button
].i
)
146 /* We fell off the end, so we lack the configured logging type */
147 if (button
== ctrl
->radio
.nbuttons
) {
149 cfg
->logtype
=LGTYP_NONE
;
151 dlg_radiobutton_set(ctrl
, dlg
, button
);
152 } else if (event
== EVENT_VALCHANGE
) {
153 button
= dlg_radiobutton_get(ctrl
, dlg
);
154 assert(button
>= 0 && button
< ctrl
->radio
.nbuttons
);
155 cfg
->logtype
= ctrl
->radio
.buttondata
[button
].i
;
159 static void numeric_keypad_handler(union control
*ctrl
, void *dlg
,
160 void *data
, int event
)
163 Config
*cfg
= (Config
*)data
;
165 * This function works much like the standard radio button
166 * handler, but it has to handle two fields in Config.
168 if (event
== EVENT_REFRESH
) {
169 if (cfg
->nethack_keypad
)
171 else if (cfg
->app_keypad
)
175 assert(button
< ctrl
->radio
.nbuttons
);
176 dlg_radiobutton_set(ctrl
, dlg
, button
);
177 } else if (event
== EVENT_VALCHANGE
) {
178 button
= dlg_radiobutton_get(ctrl
, dlg
);
179 assert(button
>= 0 && button
< ctrl
->radio
.nbuttons
);
181 cfg
->app_keypad
= FALSE
;
182 cfg
->nethack_keypad
= TRUE
;
184 cfg
->app_keypad
= (button
!= 0);
185 cfg
->nethack_keypad
= FALSE
;
190 static void cipherlist_handler(union control
*ctrl
, void *dlg
,
191 void *data
, int event
)
193 Config
*cfg
= (Config
*)data
;
194 if (event
== EVENT_REFRESH
) {
197 static const struct { char *s
; int c
; } ciphers
[] = {
198 { "3DES", CIPHER_3DES
},
199 { "Blowfish", CIPHER_BLOWFISH
},
200 { "DES", CIPHER_DES
},
201 { "AES (SSH-2 only)", CIPHER_AES
},
202 { "Arcfour (SSH-2 only)", CIPHER_ARCFOUR
},
203 { "-- warn below here --", CIPHER_WARN
}
206 /* Set up the "selected ciphers" box. */
207 /* (cipherlist assumed to contain all ciphers) */
208 dlg_update_start(ctrl
, dlg
);
209 dlg_listbox_clear(ctrl
, dlg
);
210 for (i
= 0; i
< CIPHER_MAX
; i
++) {
211 int c
= cfg
->ssh_cipherlist
[i
];
214 for (j
= 0; j
< (sizeof ciphers
) / (sizeof ciphers
[0]); j
++) {
215 if (ciphers
[j
].c
== c
) {
220 dlg_listbox_addwithid(ctrl
, dlg
, cstr
, c
);
222 dlg_update_done(ctrl
, dlg
);
224 } else if (event
== EVENT_VALCHANGE
) {
227 /* Update array to match the list box. */
228 for (i
=0; i
< CIPHER_MAX
; i
++)
229 cfg
->ssh_cipherlist
[i
] = dlg_listbox_getid(ctrl
, dlg
, i
);
234 static void kexlist_handler(union control
*ctrl
, void *dlg
,
235 void *data
, int event
)
237 Config
*cfg
= (Config
*)data
;
238 if (event
== EVENT_REFRESH
) {
241 static const struct { char *s
; int k
; } kexes
[] = {
242 { "Diffie-Hellman group 1", KEX_DHGROUP1
},
243 { "Diffie-Hellman group 14", KEX_DHGROUP14
},
244 { "Diffie-Hellman group exchange", KEX_DHGEX
},
245 { "-- warn below here --", KEX_WARN
}
248 /* Set up the "kex preference" box. */
249 /* (kexlist assumed to contain all algorithms) */
250 dlg_update_start(ctrl
, dlg
);
251 dlg_listbox_clear(ctrl
, dlg
);
252 for (i
= 0; i
< KEX_MAX
; i
++) {
253 int k
= cfg
->ssh_kexlist
[i
];
256 for (j
= 0; j
< (sizeof kexes
) / (sizeof kexes
[0]); j
++) {
257 if (kexes
[j
].k
== k
) {
262 dlg_listbox_addwithid(ctrl
, dlg
, kstr
, k
);
264 dlg_update_done(ctrl
, dlg
);
266 } else if (event
== EVENT_VALCHANGE
) {
269 /* Update array to match the list box. */
270 for (i
=0; i
< KEX_MAX
; i
++)
271 cfg
->ssh_kexlist
[i
] = dlg_listbox_getid(ctrl
, dlg
, i
);
276 static void printerbox_handler(union control
*ctrl
, void *dlg
,
277 void *data
, int event
)
279 Config
*cfg
= (Config
*)data
;
280 if (event
== EVENT_REFRESH
) {
284 dlg_update_start(ctrl
, dlg
);
286 * Some backends may wish to disable the drop-down list on
287 * this edit box. Be prepared for this.
289 if (ctrl
->editbox
.has_list
) {
290 dlg_listbox_clear(ctrl
, dlg
);
291 dlg_listbox_add(ctrl
, dlg
, PRINTER_DISABLED_STRING
);
292 pe
= printer_start_enum(&nprinters
);
293 for (i
= 0; i
< nprinters
; i
++)
294 dlg_listbox_add(ctrl
, dlg
, printer_get_name(pe
, i
));
295 printer_finish_enum(pe
);
297 dlg_editbox_set(ctrl
, dlg
,
298 (*cfg
->printer ? cfg
->printer
:
299 PRINTER_DISABLED_STRING
));
300 dlg_update_done(ctrl
, dlg
);
301 } else if (event
== EVENT_VALCHANGE
) {
302 dlg_editbox_get(ctrl
, dlg
, cfg
->printer
, sizeof(cfg
->printer
));
303 if (!strcmp(cfg
->printer
, PRINTER_DISABLED_STRING
))
304 *cfg
->printer
= '\0';
308 static void codepage_handler(union control
*ctrl
, void *dlg
,
309 void *data
, int event
)
311 Config
*cfg
= (Config
*)data
;
312 if (event
== EVENT_REFRESH
) {
315 dlg_update_start(ctrl
, dlg
);
316 strcpy(cfg
->line_codepage
,
317 cp_name(decode_codepage(cfg
->line_codepage
)));
318 dlg_listbox_clear(ctrl
, dlg
);
319 for (i
= 0; (cp
= cp_enumerate(i
)) != NULL
; i
++)
320 dlg_listbox_add(ctrl
, dlg
, cp
);
321 dlg_editbox_set(ctrl
, dlg
, cfg
->line_codepage
);
322 dlg_update_done(ctrl
, dlg
);
323 } else if (event
== EVENT_VALCHANGE
) {
324 dlg_editbox_get(ctrl
, dlg
, cfg
->line_codepage
,
325 sizeof(cfg
->line_codepage
));
326 strcpy(cfg
->line_codepage
,
327 cp_name(decode_codepage(cfg
->line_codepage
)));
331 static void sshbug_handler(union control
*ctrl
, void *dlg
,
332 void *data
, int event
)
334 if (event
== EVENT_REFRESH
) {
335 dlg_update_start(ctrl
, dlg
);
336 dlg_listbox_clear(ctrl
, dlg
);
337 dlg_listbox_addwithid(ctrl
, dlg
, "Auto", AUTO
);
338 dlg_listbox_addwithid(ctrl
, dlg
, "Off", FORCE_OFF
);
339 dlg_listbox_addwithid(ctrl
, dlg
, "On", FORCE_ON
);
340 switch (*(int *)ATOFFSET(data
, ctrl
->listbox
.context
.i
)) {
341 case AUTO
: dlg_listbox_select(ctrl
, dlg
, 0); break;
342 case FORCE_OFF
: dlg_listbox_select(ctrl
, dlg
, 1); break;
343 case FORCE_ON
: dlg_listbox_select(ctrl
, dlg
, 2); break;
345 dlg_update_done(ctrl
, dlg
);
346 } else if (event
== EVENT_SELCHANGE
) {
347 int i
= dlg_listbox_index(ctrl
, dlg
);
351 i
= dlg_listbox_getid(ctrl
, dlg
, i
);
352 *(int *)ATOFFSET(data
, ctrl
->listbox
.context
.i
) = i
;
356 #define SAVEDSESSION_LEN 2048
358 struct sessionsaver_data
{
359 union control
*editbox
, *listbox
, *loadbutton
, *savebutton
, *delbutton
;
360 union control
*okbutton
, *cancelbutton
;
361 struct sesslist sesslist
;
366 * Helper function to load the session selected in the list box, if
367 * any, as this is done in more than one place below. Returns 0 for
370 static int load_selected_session(struct sessionsaver_data
*ssd
,
372 void *dlg
, Config
*cfg
)
374 int i
= dlg_listbox_index(ssd
->listbox
, dlg
);
380 isdef
= !strcmp(ssd
->sesslist
.sessions
[i
], "Default Settings");
381 load_settings(ssd
->sesslist
.sessions
[i
], !isdef
, cfg
);
383 strncpy(savedsession
, ssd
->sesslist
.sessions
[i
],
385 savedsession
[SAVEDSESSION_LEN
-1] = '\0';
387 savedsession
[0] = '\0';
389 dlg_refresh(NULL
, dlg
);
390 /* Restore the selection, which might have been clobbered by
391 * changing the value of the edit box. */
392 dlg_listbox_select(ssd
->listbox
, dlg
, i
);
396 static void sessionsaver_handler(union control
*ctrl
, void *dlg
,
397 void *data
, int event
)
399 Config
*cfg
= (Config
*)data
;
400 struct sessionsaver_data
*ssd
=
401 (struct sessionsaver_data
*)ctrl
->generic
.context
.p
;
405 * The first time we're called in a new dialog, we must
406 * allocate space to store the current contents of the saved
407 * session edit box (since it must persist even when we switch
408 * panels, but is not part of the Config).
412 } else if (!dlg_get_privdata(ssd
->editbox
, dlg
)) {
413 savedsession
= (char *)
414 dlg_alloc_privdata(ssd
->editbox
, dlg
, SAVEDSESSION_LEN
);
415 savedsession
[0] = '\0';
417 savedsession
= dlg_get_privdata(ssd
->editbox
, dlg
);
420 if (event
== EVENT_REFRESH
) {
421 if (ctrl
== ssd
->editbox
) {
422 dlg_editbox_set(ctrl
, dlg
, savedsession
);
423 } else if (ctrl
== ssd
->listbox
) {
425 dlg_update_start(ctrl
, dlg
);
426 dlg_listbox_clear(ctrl
, dlg
);
427 for (i
= 0; i
< ssd
->sesslist
.nsessions
; i
++)
428 dlg_listbox_add(ctrl
, dlg
, ssd
->sesslist
.sessions
[i
]);
429 dlg_update_done(ctrl
, dlg
);
431 } else if (event
== EVENT_VALCHANGE
) {
432 int top
, bottom
, halfway
, i
;
433 if (ctrl
== ssd
->editbox
) {
434 dlg_editbox_get(ctrl
, dlg
, savedsession
,
436 top
= ssd
->sesslist
.nsessions
;
438 while (top
-bottom
> 1) {
439 halfway
= (top
+bottom
)/2;
440 i
= strcmp(savedsession
, ssd
->sesslist
.sessions
[halfway
]);
447 if (top
== ssd
->sesslist
.nsessions
) {
450 dlg_listbox_select(ssd
->listbox
, dlg
, top
);
452 } else if (event
== EVENT_ACTION
) {
453 if (!ssd
->midsession
&&
454 (ctrl
== ssd
->listbox
||
455 (ssd
->loadbutton
&& ctrl
== ssd
->loadbutton
))) {
457 * The user has double-clicked a session, or hit Load.
458 * We must load the selected session, and then
459 * terminate the configuration dialog _if_ there was a
460 * double-click on the list box _and_ that session
461 * contains a hostname.
463 if (load_selected_session(ssd
, savedsession
, dlg
, cfg
) &&
464 (ctrl
== ssd
->listbox
&& cfg_launchable(cfg
))) {
465 dlg_end(dlg
, 1); /* it's all over, and succeeded */
467 } else if (ctrl
== ssd
->savebutton
) {
468 int isdef
= !strcmp(savedsession
, "Default Settings");
469 if (!savedsession
[0]) {
470 int i
= dlg_listbox_index(ssd
->listbox
, dlg
);
475 isdef
= !strcmp(ssd
->sesslist
.sessions
[i
], "Default Settings");
477 strncpy(savedsession
, ssd
->sesslist
.sessions
[i
],
479 savedsession
[SAVEDSESSION_LEN
-1] = '\0';
481 savedsession
[0] = '\0';
485 char *errmsg
= save_settings(savedsession
, !isdef
, cfg
);
487 dlg_error_msg(dlg
, errmsg
);
491 get_sesslist(&ssd
->sesslist
, FALSE
);
492 get_sesslist(&ssd
->sesslist
, TRUE
);
493 dlg_refresh(ssd
->editbox
, dlg
);
494 dlg_refresh(ssd
->listbox
, dlg
);
495 } else if (!ssd
->midsession
&&
496 ssd
->delbutton
&& ctrl
== ssd
->delbutton
) {
497 int i
= dlg_listbox_index(ssd
->listbox
, dlg
);
501 del_settings(ssd
->sesslist
.sessions
[i
]);
502 get_sesslist(&ssd
->sesslist
, FALSE
);
503 get_sesslist(&ssd
->sesslist
, TRUE
);
504 dlg_refresh(ssd
->listbox
, dlg
);
506 } else if (ctrl
== ssd
->okbutton
) {
507 if (ssd
->midsession
) {
508 /* In a mid-session Change Settings, Apply is always OK. */
513 * Annoying special case. If the `Open' button is
514 * pressed while no host name is currently set, _and_
515 * the session list previously had the focus, _and_
516 * there was a session selected in that which had a
517 * valid host name in it, then load it and go.
519 if (dlg_last_focused(ctrl
, dlg
) == ssd
->listbox
&&
520 !cfg_launchable(cfg
)) {
522 if (!load_selected_session(ssd
, savedsession
, dlg
, &cfg2
)) {
526 /* If at this point we have a valid session, go! */
528 *cfg
= cfg2
; /* structure copy */
529 cfg
->remote_cmd_ptr
= NULL
;
537 * Otherwise, do the normal thing: if we have a valid
538 * session, get going.
540 if (cfg_launchable(cfg
)) {
544 } else if (ctrl
== ssd
->cancelbutton
) {
550 struct charclass_data
{
551 union control
*listbox
, *editbox
, *button
;
554 static void charclass_handler(union control
*ctrl
, void *dlg
,
555 void *data
, int event
)
557 Config
*cfg
= (Config
*)data
;
558 struct charclass_data
*ccd
=
559 (struct charclass_data
*)ctrl
->generic
.context
.p
;
561 if (event
== EVENT_REFRESH
) {
562 if (ctrl
== ccd
->listbox
) {
564 dlg_update_start(ctrl
, dlg
);
565 dlg_listbox_clear(ctrl
, dlg
);
566 for (i
= 0; i
< 128; i
++) {
568 sprintf(str
, "%d\t(0x%02X)\t%c\t%d", i
, i
,
569 (i
>= 0x21 && i
!= 0x7F) ? i
: ' ', cfg
->wordness
[i
]);
570 dlg_listbox_add(ctrl
, dlg
, str
);
572 dlg_update_done(ctrl
, dlg
);
574 } else if (event
== EVENT_ACTION
) {
575 if (ctrl
== ccd
->button
) {
578 dlg_editbox_get(ccd
->editbox
, dlg
, str
, sizeof(str
));
580 for (i
= 0; i
< 128; i
++) {
581 if (dlg_listbox_issel(ccd
->listbox
, dlg
, i
))
582 cfg
->wordness
[i
] = n
;
584 dlg_refresh(ccd
->listbox
, dlg
);
590 union control
*listbox
, *redit
, *gedit
, *bedit
, *button
;
593 static const char *const colours
[] = {
594 "Default Foreground", "Default Bold Foreground",
595 "Default Background", "Default Bold Background",
596 "Cursor Text", "Cursor Colour",
597 "ANSI Black", "ANSI Black Bold",
598 "ANSI Red", "ANSI Red Bold",
599 "ANSI Green", "ANSI Green Bold",
600 "ANSI Yellow", "ANSI Yellow Bold",
601 "ANSI Blue", "ANSI Blue Bold",
602 "ANSI Magenta", "ANSI Magenta Bold",
603 "ANSI Cyan", "ANSI Cyan Bold",
604 "ANSI White", "ANSI White Bold"
607 static void colour_handler(union control
*ctrl
, void *dlg
,
608 void *data
, int event
)
610 Config
*cfg
= (Config
*)data
;
611 struct colour_data
*cd
=
612 (struct colour_data
*)ctrl
->generic
.context
.p
;
613 int update
= FALSE
, r
, g
, b
;
615 if (event
== EVENT_REFRESH
) {
616 if (ctrl
== cd
->listbox
) {
618 dlg_update_start(ctrl
, dlg
);
619 dlg_listbox_clear(ctrl
, dlg
);
620 for (i
= 0; i
< lenof(colours
); i
++)
621 dlg_listbox_add(ctrl
, dlg
, colours
[i
]);
622 dlg_update_done(ctrl
, dlg
);
623 dlg_editbox_set(cd
->redit
, dlg
, "");
624 dlg_editbox_set(cd
->gedit
, dlg
, "");
625 dlg_editbox_set(cd
->bedit
, dlg
, "");
627 } else if (event
== EVENT_SELCHANGE
) {
628 if (ctrl
== cd
->listbox
) {
629 /* The user has selected a colour. Update the RGB text. */
630 int i
= dlg_listbox_index(ctrl
, dlg
);
635 r
= cfg
->colours
[i
][0];
636 g
= cfg
->colours
[i
][1];
637 b
= cfg
->colours
[i
][2];
640 } else if (event
== EVENT_VALCHANGE
) {
641 if (ctrl
== cd
->redit
|| ctrl
== cd
->gedit
|| ctrl
== cd
->bedit
) {
642 /* The user has changed the colour using the edit boxes. */
646 dlg_editbox_get(ctrl
, dlg
, buf
, lenof(buf
));
648 if (cval
> 255) cval
= 255;
649 if (cval
< 0) cval
= 0;
651 i
= dlg_listbox_index(cd
->listbox
, dlg
);
653 if (ctrl
== cd
->redit
)
654 cfg
->colours
[i
][0] = cval
;
655 else if (ctrl
== cd
->gedit
)
656 cfg
->colours
[i
][1] = cval
;
657 else if (ctrl
== cd
->bedit
)
658 cfg
->colours
[i
][2] = cval
;
661 } else if (event
== EVENT_ACTION
) {
662 if (ctrl
== cd
->button
) {
663 int i
= dlg_listbox_index(cd
->listbox
, dlg
);
669 * Start a colour selector, which will send us an
670 * EVENT_CALLBACK when it's finished and allow us to
671 * pick up the results.
673 dlg_coloursel_start(ctrl
, dlg
,
678 } else if (event
== EVENT_CALLBACK
) {
679 if (ctrl
== cd
->button
) {
680 int i
= dlg_listbox_index(cd
->listbox
, dlg
);
682 * Collect the results of the colour selector. Will
683 * return nonzero on success, or zero if the colour
684 * selector did nothing (user hit Cancel, for example).
686 if (dlg_coloursel_results(ctrl
, dlg
, &r
, &g
, &b
)) {
687 cfg
->colours
[i
][0] = r
;
688 cfg
->colours
[i
][1] = g
;
689 cfg
->colours
[i
][2] = b
;
697 sprintf(buf
, "%d", r
); dlg_editbox_set(cd
->redit
, dlg
, buf
);
698 sprintf(buf
, "%d", g
); dlg_editbox_set(cd
->gedit
, dlg
, buf
);
699 sprintf(buf
, "%d", b
); dlg_editbox_set(cd
->bedit
, dlg
, buf
);
703 struct ttymodes_data
{
704 union control
*modelist
, *valradio
, *valbox
;
705 union control
*addbutton
, *rembutton
, *listbox
;
708 static void ttymodes_handler(union control
*ctrl
, void *dlg
,
709 void *data
, int event
)
711 Config
*cfg
= (Config
*)data
;
712 struct ttymodes_data
*td
=
713 (struct ttymodes_data
*)ctrl
->generic
.context
.p
;
715 if (event
== EVENT_REFRESH
) {
716 if (ctrl
== td
->listbox
) {
717 char *p
= cfg
->ttymodes
;
718 dlg_update_start(ctrl
, dlg
);
719 dlg_listbox_clear(ctrl
, dlg
);
721 int tabpos
= strchr(p
, '\t') - p
;
722 char *disp
= dupprintf("%.*s\t%s", tabpos
, p
,
723 (p
[tabpos
+1] == 'A') ?
"(auto)" :
725 dlg_listbox_add(ctrl
, dlg
, disp
);
729 dlg_update_done(ctrl
, dlg
);
730 } else if (ctrl
== td
->modelist
) {
732 dlg_update_start(ctrl
, dlg
);
733 dlg_listbox_clear(ctrl
, dlg
);
734 for (i
= 0; ttymodes
[i
]; i
++)
735 dlg_listbox_add(ctrl
, dlg
, ttymodes
[i
]);
736 dlg_listbox_select(ctrl
, dlg
, 0); /* *shrug* */
737 dlg_update_done(ctrl
, dlg
);
738 } else if (ctrl
== td
->valradio
) {
739 dlg_radiobutton_set(ctrl
, dlg
, 0);
741 } else if (event
== EVENT_ACTION
) {
742 if (ctrl
== td
->addbutton
) {
743 int ind
= dlg_listbox_index(td
->modelist
, dlg
);
745 char type
= dlg_radiobutton_get(td
->valradio
, dlg
) ?
'V' : 'A';
747 char *p
, str
[lenof(cfg
->ttymodes
)];
748 /* Construct new entry */
749 memset(str
, 0, lenof(str
));
750 strncpy(str
, ttymodes
[ind
], lenof(str
)-3);
756 dlg_editbox_get(td
->valbox
, dlg
, str
+slen
, lenof(str
)-slen
);
758 /* Find end of list, deleting any existing instance */
760 left
= lenof(cfg
->ttymodes
);
762 int t
= strchr(p
, '\t') - p
;
763 if (t
== strlen(ttymodes
[ind
]) &&
764 strncmp(p
, ttymodes
[ind
], t
) == 0) {
765 memmove(p
, p
+strlen(p
)+1, left
- (strlen(p
)+1));
768 left
-= strlen(p
) + 1;
771 /* Append new entry */
773 strncpy(p
, str
, left
- 2);
774 dlg_refresh(td
->listbox
, dlg
);
777 } else if (ctrl
== td
->rembutton
) {
778 char *p
= cfg
->ttymodes
;
779 int i
= 0, len
= lenof(cfg
->ttymodes
);
781 if (dlg_listbox_issel(td
->listbox
, dlg
, i
)) {
782 memmove(p
, p
+strlen(p
)+1, len
- (strlen(p
)+1));
786 len
-= strlen(p
) + 1;
790 memset(p
, 0, lenof(cfg
->ttymodes
) - len
);
791 dlg_refresh(td
->listbox
, dlg
);
796 struct environ_data
{
797 union control
*varbox
, *valbox
, *addbutton
, *rembutton
, *listbox
;
800 static void environ_handler(union control
*ctrl
, void *dlg
,
801 void *data
, int event
)
803 Config
*cfg
= (Config
*)data
;
804 struct environ_data
*ed
=
805 (struct environ_data
*)ctrl
->generic
.context
.p
;
807 if (event
== EVENT_REFRESH
) {
808 if (ctrl
== ed
->listbox
) {
809 char *p
= cfg
->environmt
;
810 dlg_update_start(ctrl
, dlg
);
811 dlg_listbox_clear(ctrl
, dlg
);
813 dlg_listbox_add(ctrl
, dlg
, p
);
816 dlg_update_done(ctrl
, dlg
);
818 } else if (event
== EVENT_ACTION
) {
819 if (ctrl
== ed
->addbutton
) {
820 char str
[sizeof(cfg
->environmt
)];
822 dlg_editbox_get(ed
->varbox
, dlg
, str
, sizeof(str
)-1);
827 p
= str
+ strlen(str
);
829 dlg_editbox_get(ed
->valbox
, dlg
, p
, sizeof(str
)-1 - (p
- str
));
840 if ((p
- cfg
->environmt
) + strlen(str
) + 2 <
841 sizeof(cfg
->environmt
)) {
843 p
[strlen(str
) + 1] = '\0';
844 dlg_listbox_add(ed
->listbox
, dlg
, str
);
845 dlg_editbox_set(ed
->varbox
, dlg
, "");
846 dlg_editbox_set(ed
->valbox
, dlg
, "");
848 dlg_error_msg(dlg
, "Environment too big");
850 } else if (ctrl
== ed
->rembutton
) {
851 int i
= dlg_listbox_index(ed
->listbox
, dlg
);
857 dlg_listbox_del(ed
->listbox
, dlg
, i
);
885 struct portfwd_data
{
886 union control
*addbutton
, *rembutton
, *listbox
;
887 union control
*sourcebox
, *destbox
, *direction
;
889 union control
*addressfamily
;
893 static void portfwd_handler(union control
*ctrl
, void *dlg
,
894 void *data
, int event
)
896 Config
*cfg
= (Config
*)data
;
897 struct portfwd_data
*pfd
=
898 (struct portfwd_data
*)ctrl
->generic
.context
.p
;
900 if (event
== EVENT_REFRESH
) {
901 if (ctrl
== pfd
->listbox
) {
902 char *p
= cfg
->portfwd
;
903 dlg_update_start(ctrl
, dlg
);
904 dlg_listbox_clear(ctrl
, dlg
);
906 dlg_listbox_add(ctrl
, dlg
, p
);
909 dlg_update_done(ctrl
, dlg
);
910 } else if (ctrl
== pfd
->direction
) {
914 dlg_radiobutton_set(ctrl
, dlg
, 0);
916 } else if (ctrl
== pfd
->addressfamily
) {
917 dlg_radiobutton_set(ctrl
, dlg
, 0);
920 } else if (event
== EVENT_ACTION
) {
921 if (ctrl
== pfd
->addbutton
) {
922 char str
[sizeof(cfg
->portfwd
)];
929 whichbutton
= dlg_radiobutton_get(pfd
->addressfamily
, dlg
);
930 if (whichbutton
== 1)
932 else if (whichbutton
== 2)
936 whichbutton
= dlg_radiobutton_get(pfd
->direction
, dlg
);
937 if (whichbutton
== 0)
939 else if (whichbutton
== 1)
945 dlg_editbox_get(pfd
->sourcebox
, dlg
, str
+i
, sizeof(str
) - i
);
947 dlg_error_msg(dlg
, "You need to specify a source port number");
950 p
= str
+ strlen(str
);
953 dlg_editbox_get(pfd
->destbox
, dlg
, p
,
954 sizeof(str
) - (p
- str
));
955 if (!*p
|| !strchr(p
, ':')) {
957 "You need to specify a destination address\n"
958 "in the form \"host.name:port\"");
969 if ((p
- cfg
->portfwd
) + strlen(str
) + 2 <=
970 sizeof(cfg
->portfwd
)) {
972 p
[strlen(str
) + 1] = '\0';
973 dlg_listbox_add(pfd
->listbox
, dlg
, str
);
974 dlg_editbox_set(pfd
->sourcebox
, dlg
, "");
975 dlg_editbox_set(pfd
->destbox
, dlg
, "");
977 dlg_error_msg(dlg
, "Too many forwardings");
979 } else if (ctrl
== pfd
->rembutton
) {
980 int i
= dlg_listbox_index(pfd
->listbox
, dlg
);
986 dlg_listbox_del(pfd
->listbox
, dlg
, i
);
1014 void setup_config_box(struct controlbox
*b
, int midsession
,
1015 int protocol
, int protcfginfo
)
1017 struct controlset
*s
;
1018 struct sessionsaver_data
*ssd
;
1019 struct charclass_data
*ccd
;
1020 struct colour_data
*cd
;
1021 struct ttymodes_data
*td
;
1022 struct environ_data
*ed
;
1023 struct portfwd_data
*pfd
;
1027 ssd
= (struct sessionsaver_data
*)
1028 ctrl_alloc(b
, sizeof(struct sessionsaver_data
));
1029 memset(ssd
, 0, sizeof(*ssd
));
1030 ssd
->midsession
= midsession
;
1033 * The standard panel that appears at the bottom of all panels:
1034 * Open, Cancel, Apply etc.
1036 s
= ctrl_getset(b
, "", "", "");
1037 ctrl_columns(s
, 5, 20, 20, 20, 20, 20);
1038 ssd
->okbutton
= ctrl_pushbutton(s
,
1039 (midsession ?
"Apply" : "Open"),
1040 (char)(midsession ?
'a' : 'o'),
1042 sessionsaver_handler
, P(ssd
));
1043 ssd
->okbutton
->button
.isdefault
= TRUE
;
1044 ssd
->okbutton
->generic
.column
= 3;
1045 ssd
->cancelbutton
= ctrl_pushbutton(s
, "Cancel", 'c', HELPCTX(no_help
),
1046 sessionsaver_handler
, P(ssd
));
1047 ssd
->cancelbutton
->button
.iscancel
= TRUE
;
1048 ssd
->cancelbutton
->generic
.column
= 4;
1049 /* We carefully don't close the 5-column part, so that platform-
1050 * specific add-ons can put extra buttons alongside Open and Cancel. */
1053 * The Session panel.
1055 str
= dupprintf("Basic options for your %s session", appname
);
1056 ctrl_settitle(b
, "Session", str
);
1060 struct hostport
*hp
= (struct hostport
*)
1061 ctrl_alloc(b
, sizeof(struct hostport
));
1064 s
= ctrl_getset(b
, "Session", "hostport",
1065 "Specify the destination you want to connect to");
1066 ctrl_columns(s
, 2, 75, 25);
1067 c
= ctrl_editbox(s
, HOST_BOX_TITLE
, 'n', 100,
1068 HELPCTX(session_hostname
),
1069 config_host_handler
, I(0), I(0));
1070 c
->generic
.column
= 0;
1072 c
= ctrl_editbox(s
, PORT_BOX_TITLE
, 'p', 100,
1073 HELPCTX(session_hostname
),
1074 config_port_handler
, I(0), I(0));
1075 c
->generic
.column
= 1;
1077 ctrl_columns(s
, 1, 100);
1080 for (i
= 0; backends
[i
].name
; i
++)
1081 if (backends
[i
].protocol
== PROT_SSH
) {
1086 ctrl_radiobuttons(s
, "Connection type:", NO_SHORTCUT
, 3,
1087 HELPCTX(session_hostname
),
1088 config_protocolbuttons_handler
, P(hp
),
1089 "Raw", 'r', I(PROT_RAW
),
1090 "Telnet", 't', I(PROT_TELNET
),
1091 "Rlogin", 'i', I(PROT_RLOGIN
),
1094 ctrl_radiobuttons(s
, "Connection type:", NO_SHORTCUT
, 4,
1095 HELPCTX(session_hostname
),
1096 config_protocolbuttons_handler
, P(hp
),
1097 "Raw", 'r', I(PROT_RAW
),
1098 "Telnet", 't', I(PROT_TELNET
),
1099 "Rlogin", 'i', I(PROT_RLOGIN
),
1100 "SSH", 's', I(PROT_SSH
),
1106 * The Load/Save panel is available even in mid-session.
1108 s
= ctrl_getset(b
, "Session", "savedsessions",
1109 midsession ?
"Save the current session settings" :
1110 "Load, save or delete a stored session");
1111 ctrl_columns(s
, 2, 75, 25);
1112 get_sesslist(&ssd
->sesslist
, TRUE
);
1113 ssd
->editbox
= ctrl_editbox(s
, "Saved Sessions", 'e', 100,
1114 HELPCTX(session_saved
),
1115 sessionsaver_handler
, P(ssd
), P(NULL
));
1116 ssd
->editbox
->generic
.column
= 0;
1117 /* Reset columns so that the buttons are alongside the list, rather
1118 * than alongside that edit box. */
1119 ctrl_columns(s
, 1, 100);
1120 ctrl_columns(s
, 2, 75, 25);
1121 ssd
->listbox
= ctrl_listbox(s
, NULL
, NO_SHORTCUT
,
1122 HELPCTX(session_saved
),
1123 sessionsaver_handler
, P(ssd
));
1124 ssd
->listbox
->generic
.column
= 0;
1125 ssd
->listbox
->listbox
.height
= 7;
1127 ssd
->loadbutton
= ctrl_pushbutton(s
, "Load", 'l',
1128 HELPCTX(session_saved
),
1129 sessionsaver_handler
, P(ssd
));
1130 ssd
->loadbutton
->generic
.column
= 1;
1132 /* We can't offer the Load button mid-session, as it would allow the
1133 * user to load and subsequently save settings they can't see. (And
1134 * also change otherwise immutable settings underfoot; that probably
1135 * shouldn't be a problem, but.) */
1136 ssd
->loadbutton
= NULL
;
1138 /* "Save" button is permitted mid-session. */
1139 ssd
->savebutton
= ctrl_pushbutton(s
, "Save", 'v',
1140 HELPCTX(session_saved
),
1141 sessionsaver_handler
, P(ssd
));
1142 ssd
->savebutton
->generic
.column
= 1;
1144 ssd
->delbutton
= ctrl_pushbutton(s
, "Delete", 'd',
1145 HELPCTX(session_saved
),
1146 sessionsaver_handler
, P(ssd
));
1147 ssd
->delbutton
->generic
.column
= 1;
1149 /* Disable the Delete button mid-session too, for UI consistency. */
1150 ssd
->delbutton
= NULL
;
1152 ctrl_columns(s
, 1, 100);
1154 s
= ctrl_getset(b
, "Session", "otheropts", NULL
);
1155 c
= ctrl_radiobuttons(s
, "Close window on exit:", 'w', 4,
1156 HELPCTX(session_coe
),
1157 dlg_stdradiobutton_handler
,
1158 I(offsetof(Config
, close_on_exit
)),
1159 "Always", I(FORCE_ON
),
1160 "Never", I(FORCE_OFF
),
1161 "Only on clean exit", I(AUTO
), NULL
);
1164 * The Session/Logging panel.
1166 ctrl_settitle(b
, "Session/Logging", "Options controlling session logging");
1168 s
= ctrl_getset(b
, "Session/Logging", "main", NULL
);
1170 * The logging buttons change depending on whether SSH packet
1171 * logging can sensibly be available.
1174 char *sshlogname
, *sshrawlogname
;
1175 if ((midsession
&& protocol
== PROT_SSH
) ||
1176 (!midsession
&& backends
[3].name
!= NULL
)) {
1177 sshlogname
= "SSH packets";
1178 sshrawlogname
= "SSH packets and raw data";
1180 sshlogname
= NULL
; /* this will disable both buttons */
1181 sshrawlogname
= NULL
; /* this will just placate optimisers */
1183 ctrl_radiobuttons(s
, "Session logging:", NO_SHORTCUT
, 2,
1184 HELPCTX(logging_main
),
1185 loggingbuttons_handler
,
1186 I(offsetof(Config
, logtype
)),
1187 "None", 't', I(LGTYP_NONE
),
1188 "Printable output", 'p', I(LGTYP_ASCII
),
1189 "All session output", 'l', I(LGTYP_DEBUG
),
1190 sshlogname
, 's', I(LGTYP_PACKETS
),
1191 sshrawlogname
, 'r', I(LGTYP_SSHRAW
),
1194 ctrl_filesel(s
, "Log file name:", 'f',
1195 NULL
, TRUE
, "Select session log file name",
1196 HELPCTX(logging_filename
),
1197 dlg_stdfilesel_handler
, I(offsetof(Config
, logfilename
)));
1198 ctrl_text(s
, "(Log file name can contain &Y, &M, &D for date,"
1199 " &T for time, and &H for host name)",
1200 HELPCTX(logging_filename
));
1201 ctrl_radiobuttons(s
, "What to do if the log file already exists:", 'e', 1,
1202 HELPCTX(logging_exists
),
1203 dlg_stdradiobutton_handler
, I(offsetof(Config
,logxfovr
)),
1204 "Always overwrite it", I(LGXF_OVR
),
1205 "Always append to the end of it", I(LGXF_APN
),
1206 "Ask the user every time", I(LGXF_ASK
), NULL
);
1207 ctrl_checkbox(s
, "Flush log file frequently", 'u',
1208 HELPCTX(logging_flush
),
1209 dlg_stdcheckbox_handler
, I(offsetof(Config
,logflush
)));
1211 if ((midsession
&& protocol
== PROT_SSH
) ||
1212 (!midsession
&& backends
[3].name
!= NULL
)) {
1213 s
= ctrl_getset(b
, "Session/Logging", "ssh",
1214 "Options specific to SSH packet logging");
1215 ctrl_checkbox(s
, "Omit known password fields", 'k',
1216 HELPCTX(logging_ssh_omit_password
),
1217 dlg_stdcheckbox_handler
, I(offsetof(Config
,logomitpass
)));
1218 ctrl_checkbox(s
, "Omit session data", 'd',
1219 HELPCTX(logging_ssh_omit_data
),
1220 dlg_stdcheckbox_handler
, I(offsetof(Config
,logomitdata
)));
1224 * The Terminal panel.
1226 ctrl_settitle(b
, "Terminal", "Options controlling the terminal emulation");
1228 s
= ctrl_getset(b
, "Terminal", "general", "Set various terminal options");
1229 ctrl_checkbox(s
, "Auto wrap mode initially on", 'w',
1230 HELPCTX(terminal_autowrap
),
1231 dlg_stdcheckbox_handler
, I(offsetof(Config
,wrap_mode
)));
1232 ctrl_checkbox(s
, "DEC Origin Mode initially on", 'd',
1233 HELPCTX(terminal_decom
),
1234 dlg_stdcheckbox_handler
, I(offsetof(Config
,dec_om
)));
1235 ctrl_checkbox(s
, "Implicit CR in every LF", 'r',
1236 HELPCTX(terminal_lfhascr
),
1237 dlg_stdcheckbox_handler
, I(offsetof(Config
,lfhascr
)));
1238 ctrl_checkbox(s
, "Use background colour to erase screen", 'e',
1239 HELPCTX(terminal_bce
),
1240 dlg_stdcheckbox_handler
, I(offsetof(Config
,bce
)));
1241 ctrl_checkbox(s
, "Enable blinking text", 'n',
1242 HELPCTX(terminal_blink
),
1243 dlg_stdcheckbox_handler
, I(offsetof(Config
,blinktext
)));
1244 ctrl_editbox(s
, "Answerback to ^E:", 's', 100,
1245 HELPCTX(terminal_answerback
),
1246 dlg_stdeditbox_handler
, I(offsetof(Config
,answerback
)),
1247 I(sizeof(((Config
*)0)->answerback
)));
1249 s
= ctrl_getset(b
, "Terminal", "ldisc", "Line discipline options");
1250 ctrl_radiobuttons(s
, "Local echo:", 'l', 3,
1251 HELPCTX(terminal_localecho
),
1252 dlg_stdradiobutton_handler
,I(offsetof(Config
,localecho
)),
1254 "Force on", I(FORCE_ON
),
1255 "Force off", I(FORCE_OFF
), NULL
);
1256 ctrl_radiobuttons(s
, "Local line editing:", 't', 3,
1257 HELPCTX(terminal_localedit
),
1258 dlg_stdradiobutton_handler
,I(offsetof(Config
,localedit
)),
1260 "Force on", I(FORCE_ON
),
1261 "Force off", I(FORCE_OFF
), NULL
);
1263 s
= ctrl_getset(b
, "Terminal", "printing", "Remote-controlled printing");
1264 ctrl_combobox(s
, "Printer to send ANSI printer output to:", 'p', 100,
1265 HELPCTX(terminal_printing
),
1266 printerbox_handler
, P(NULL
), P(NULL
));
1269 * The Terminal/Keyboard panel.
1271 ctrl_settitle(b
, "Terminal/Keyboard",
1272 "Options controlling the effects of keys");
1274 s
= ctrl_getset(b
, "Terminal/Keyboard", "mappings",
1275 "Change the sequences sent by:");
1276 ctrl_radiobuttons(s
, "The Backspace key", 'b', 2,
1277 HELPCTX(keyboard_backspace
),
1278 dlg_stdradiobutton_handler
,
1279 I(offsetof(Config
, bksp_is_delete
)),
1280 "Control-H", I(0), "Control-? (127)", I(1), NULL
);
1281 ctrl_radiobuttons(s
, "The Home and End keys", 'e', 2,
1282 HELPCTX(keyboard_homeend
),
1283 dlg_stdradiobutton_handler
,
1284 I(offsetof(Config
, rxvt_homeend
)),
1285 "Standard", I(0), "rxvt", I(1), NULL
);
1286 ctrl_radiobuttons(s
, "The Function keys and keypad", 'f', 3,
1287 HELPCTX(keyboard_funkeys
),
1288 dlg_stdradiobutton_handler
,
1289 I(offsetof(Config
, funky_type
)),
1290 "ESC[n~", I(0), "Linux", I(1), "Xterm R6", I(2),
1291 "VT400", I(3), "VT100+", I(4), "SCO", I(5), NULL
);
1293 s
= ctrl_getset(b
, "Terminal/Keyboard", "appkeypad",
1294 "Application keypad settings:");
1295 ctrl_radiobuttons(s
, "Initial state of cursor keys:", 'r', 3,
1296 HELPCTX(keyboard_appcursor
),
1297 dlg_stdradiobutton_handler
,
1298 I(offsetof(Config
, app_cursor
)),
1299 "Normal", I(0), "Application", I(1), NULL
);
1300 ctrl_radiobuttons(s
, "Initial state of numeric keypad:", 'n', 3,
1301 HELPCTX(keyboard_appkeypad
),
1302 numeric_keypad_handler
, P(NULL
),
1303 "Normal", I(0), "Application", I(1), "NetHack", I(2),
1307 * The Terminal/Bell panel.
1309 ctrl_settitle(b
, "Terminal/Bell",
1310 "Options controlling the terminal bell");
1312 s
= ctrl_getset(b
, "Terminal/Bell", "style", "Set the style of bell");
1313 ctrl_radiobuttons(s
, "Action to happen when a bell occurs:", 'b', 1,
1314 HELPCTX(bell_style
),
1315 dlg_stdradiobutton_handler
, I(offsetof(Config
, beep
)),
1316 "None (bell disabled)", I(BELL_DISABLED
),
1317 "Make default system alert sound", I(BELL_DEFAULT
),
1318 "Visual bell (flash window)", I(BELL_VISUAL
), NULL
);
1320 s
= ctrl_getset(b
, "Terminal/Bell", "overload",
1321 "Control the bell overload behaviour");
1322 ctrl_checkbox(s
, "Bell is temporarily disabled when over-used", 'd',
1323 HELPCTX(bell_overload
),
1324 dlg_stdcheckbox_handler
, I(offsetof(Config
,bellovl
)));
1325 ctrl_editbox(s
, "Over-use means this many bells...", 'm', 20,
1326 HELPCTX(bell_overload
),
1327 dlg_stdeditbox_handler
, I(offsetof(Config
,bellovl_n
)), I(-1));
1328 ctrl_editbox(s
, "... in this many seconds", 't', 20,
1329 HELPCTX(bell_overload
),
1330 dlg_stdeditbox_handler
, I(offsetof(Config
,bellovl_t
)),
1332 ctrl_text(s
, "The bell is re-enabled after a few seconds of silence.",
1333 HELPCTX(bell_overload
));
1334 ctrl_editbox(s
, "Seconds of silence required", 's', 20,
1335 HELPCTX(bell_overload
),
1336 dlg_stdeditbox_handler
, I(offsetof(Config
,bellovl_s
)),
1340 * The Terminal/Features panel.
1342 ctrl_settitle(b
, "Terminal/Features",
1343 "Enabling and disabling advanced terminal features");
1345 s
= ctrl_getset(b
, "Terminal/Features", "main", NULL
);
1346 ctrl_checkbox(s
, "Disable application cursor keys mode", 'u',
1347 HELPCTX(features_application
),
1348 dlg_stdcheckbox_handler
, I(offsetof(Config
,no_applic_c
)));
1349 ctrl_checkbox(s
, "Disable application keypad mode", 'k',
1350 HELPCTX(features_application
),
1351 dlg_stdcheckbox_handler
, I(offsetof(Config
,no_applic_k
)));
1352 ctrl_checkbox(s
, "Disable xterm-style mouse reporting", 'x',
1353 HELPCTX(features_mouse
),
1354 dlg_stdcheckbox_handler
, I(offsetof(Config
,no_mouse_rep
)));
1355 ctrl_checkbox(s
, "Disable remote-controlled terminal resizing", 's',
1356 HELPCTX(features_resize
),
1357 dlg_stdcheckbox_handler
,
1358 I(offsetof(Config
,no_remote_resize
)));
1359 ctrl_checkbox(s
, "Disable switching to alternate terminal screen", 'w',
1360 HELPCTX(features_altscreen
),
1361 dlg_stdcheckbox_handler
, I(offsetof(Config
,no_alt_screen
)));
1362 ctrl_checkbox(s
, "Disable remote-controlled window title changing", 't',
1363 HELPCTX(features_retitle
),
1364 dlg_stdcheckbox_handler
,
1365 I(offsetof(Config
,no_remote_wintitle
)));
1366 ctrl_radiobuttons(s
, "Response to remote title query (SECURITY):", 'q', 3,
1367 HELPCTX(features_qtitle
),
1368 dlg_stdradiobutton_handler
,
1369 I(offsetof(Config
,remote_qtitle_action
)),
1370 "None", I(TITLE_NONE
),
1371 "Empty string", I(TITLE_EMPTY
),
1372 "Window title", I(TITLE_REAL
), NULL
);
1373 ctrl_checkbox(s
, "Disable destructive backspace on server sending ^?",'b',
1374 HELPCTX(features_dbackspace
),
1375 dlg_stdcheckbox_handler
, I(offsetof(Config
,no_dbackspace
)));
1376 ctrl_checkbox(s
, "Disable remote-controlled character set configuration",
1377 'r', HELPCTX(features_charset
), dlg_stdcheckbox_handler
,
1378 I(offsetof(Config
,no_remote_charset
)));
1379 ctrl_checkbox(s
, "Disable Arabic text shaping",
1380 'l', HELPCTX(features_arabicshaping
), dlg_stdcheckbox_handler
,
1381 I(offsetof(Config
, arabicshaping
)));
1382 ctrl_checkbox(s
, "Disable bidirectional text display",
1383 'd', HELPCTX(features_bidi
), dlg_stdcheckbox_handler
,
1384 I(offsetof(Config
, bidi
)));
1389 str
= dupprintf("Options controlling %s's window", appname
);
1390 ctrl_settitle(b
, "Window", str
);
1393 s
= ctrl_getset(b
, "Window", "size", "Set the size of the window");
1394 ctrl_columns(s
, 2, 50, 50);
1395 c
= ctrl_editbox(s
, "Rows", 'r', 100,
1396 HELPCTX(window_size
),
1397 dlg_stdeditbox_handler
, I(offsetof(Config
,height
)),I(-1));
1398 c
->generic
.column
= 0;
1399 c
= ctrl_editbox(s
, "Columns", 'm', 100,
1400 HELPCTX(window_size
),
1401 dlg_stdeditbox_handler
, I(offsetof(Config
,width
)), I(-1));
1402 c
->generic
.column
= 1;
1403 ctrl_columns(s
, 1, 100);
1405 s
= ctrl_getset(b
, "Window", "scrollback",
1406 "Control the scrollback in the window");
1407 ctrl_editbox(s
, "Lines of scrollback", 's', 50,
1408 HELPCTX(window_scrollback
),
1409 dlg_stdeditbox_handler
, I(offsetof(Config
,savelines
)), I(-1));
1410 ctrl_checkbox(s
, "Display scrollbar", 'd',
1411 HELPCTX(window_scrollback
),
1412 dlg_stdcheckbox_handler
, I(offsetof(Config
,scrollbar
)));
1413 ctrl_checkbox(s
, "Reset scrollback on keypress", 'k',
1414 HELPCTX(window_scrollback
),
1415 dlg_stdcheckbox_handler
, I(offsetof(Config
,scroll_on_key
)));
1416 ctrl_checkbox(s
, "Reset scrollback on display activity", 'p',
1417 HELPCTX(window_scrollback
),
1418 dlg_stdcheckbox_handler
, I(offsetof(Config
,scroll_on_disp
)));
1419 ctrl_checkbox(s
, "Push erased text into scrollback", 'e',
1420 HELPCTX(window_erased
),
1421 dlg_stdcheckbox_handler
,
1422 I(offsetof(Config
,erase_to_scrollback
)));
1425 * The Window/Appearance panel.
1427 str
= dupprintf("Configure the appearance of %s's window", appname
);
1428 ctrl_settitle(b
, "Window/Appearance", str
);
1431 s
= ctrl_getset(b
, "Window/Appearance", "cursor",
1432 "Adjust the use of the cursor");
1433 ctrl_radiobuttons(s
, "Cursor appearance:", NO_SHORTCUT
, 3,
1434 HELPCTX(appearance_cursor
),
1435 dlg_stdradiobutton_handler
,
1436 I(offsetof(Config
, cursor_type
)),
1438 "Underline", 'u', I(1),
1439 "Vertical line", 'v', I(2), NULL
);
1440 ctrl_checkbox(s
, "Cursor blinks", 'b',
1441 HELPCTX(appearance_cursor
),
1442 dlg_stdcheckbox_handler
, I(offsetof(Config
,blink_cur
)));
1444 s
= ctrl_getset(b
, "Window/Appearance", "font",
1446 ctrl_fontsel(s
, "Font used in the terminal window", 'n',
1447 HELPCTX(appearance_font
),
1448 dlg_stdfontsel_handler
, I(offsetof(Config
, font
)));
1450 s
= ctrl_getset(b
, "Window/Appearance", "mouse",
1451 "Adjust the use of the mouse pointer");
1452 ctrl_checkbox(s
, "Hide mouse pointer when typing in window", 'p',
1453 HELPCTX(appearance_hidemouse
),
1454 dlg_stdcheckbox_handler
, I(offsetof(Config
,hide_mouseptr
)));
1456 s
= ctrl_getset(b
, "Window/Appearance", "border",
1457 "Adjust the window border");
1458 ctrl_editbox(s
, "Gap between text and window edge:", 'e', 20,
1459 HELPCTX(appearance_border
),
1460 dlg_stdeditbox_handler
,
1461 I(offsetof(Config
,window_border
)), I(-1));
1464 * The Window/Behaviour panel.
1466 str
= dupprintf("Configure the behaviour of %s's window", appname
);
1467 ctrl_settitle(b
, "Window/Behaviour", str
);
1470 s
= ctrl_getset(b
, "Window/Behaviour", "title",
1471 "Adjust the behaviour of the window title");
1472 ctrl_editbox(s
, "Window title:", 't', 100,
1473 HELPCTX(appearance_title
),
1474 dlg_stdeditbox_handler
, I(offsetof(Config
,wintitle
)),
1475 I(sizeof(((Config
*)0)->wintitle
)));
1476 ctrl_checkbox(s
, "Separate window and icon titles", 'i',
1477 HELPCTX(appearance_title
),
1478 dlg_stdcheckbox_handler
,
1479 I(CHECKBOX_INVERT
| offsetof(Config
,win_name_always
)));
1481 s
= ctrl_getset(b
, "Window/Behaviour", "main", NULL
);
1482 ctrl_checkbox(s
, "Warn before closing window", 'w',
1483 HELPCTX(behaviour_closewarn
),
1484 dlg_stdcheckbox_handler
, I(offsetof(Config
,warn_on_close
)));
1487 * The Window/Translation panel.
1489 ctrl_settitle(b
, "Window/Translation",
1490 "Options controlling character set translation");
1492 s
= ctrl_getset(b
, "Window/Translation", "trans",
1493 "Character set translation on received data");
1494 ctrl_combobox(s
, "Received data assumed to be in which character set:",
1495 'r', 100, HELPCTX(translation_codepage
),
1496 codepage_handler
, P(NULL
), P(NULL
));
1498 s
= ctrl_getset(b
, "Window/Translation", "tweaks", NULL
);
1499 ctrl_checkbox(s
, "Treat CJK ambiguous characters as wide", 'w',
1500 HELPCTX(translation_cjk_ambig_wide
),
1501 dlg_stdcheckbox_handler
, I(offsetof(Config
,cjk_ambig_wide
)));
1503 str
= dupprintf("Adjust how %s handles line drawing characters", appname
);
1504 s
= ctrl_getset(b
, "Window/Translation", "linedraw", str
);
1506 ctrl_radiobuttons(s
, "Handling of line drawing characters:", NO_SHORTCUT
,1,
1507 HELPCTX(translation_linedraw
),
1508 dlg_stdradiobutton_handler
,
1509 I(offsetof(Config
, vtmode
)),
1510 "Use Unicode line drawing code points",'u',I(VT_UNICODE
),
1511 "Poor man's line drawing (+, - and |)",'p',I(VT_POORMAN
),
1513 ctrl_checkbox(s
, "Copy and paste line drawing characters as lqqqk",'d',
1514 HELPCTX(selection_linedraw
),
1515 dlg_stdcheckbox_handler
, I(offsetof(Config
,rawcnp
)));
1518 * The Window/Selection panel.
1520 ctrl_settitle(b
, "Window/Selection", "Options controlling copy and paste");
1522 s
= ctrl_getset(b
, "Window/Selection", "mouse",
1523 "Control use of mouse");
1524 ctrl_checkbox(s
, "Shift overrides application's use of mouse", 'p',
1525 HELPCTX(selection_shiftdrag
),
1526 dlg_stdcheckbox_handler
, I(offsetof(Config
,mouse_override
)));
1527 ctrl_radiobuttons(s
,
1528 "Default selection mode (Alt+drag does the other one):",
1530 HELPCTX(selection_rect
),
1531 dlg_stdradiobutton_handler
,
1532 I(offsetof(Config
, rect_select
)),
1533 "Normal", 'n', I(0),
1534 "Rectangular block", 'r', I(1), NULL
);
1536 s
= ctrl_getset(b
, "Window/Selection", "charclass",
1537 "Control the select-one-word-at-a-time mode");
1538 ccd
= (struct charclass_data
*)
1539 ctrl_alloc(b
, sizeof(struct charclass_data
));
1540 ccd
->listbox
= ctrl_listbox(s
, "Character classes:", 'e',
1541 HELPCTX(selection_charclasses
),
1542 charclass_handler
, P(ccd
));
1543 ccd
->listbox
->listbox
.multisel
= 1;
1544 ccd
->listbox
->listbox
.ncols
= 4;
1545 ccd
->listbox
->listbox
.percentages
= snewn(4, int);
1546 ccd
->listbox
->listbox
.percentages
[0] = 15;
1547 ccd
->listbox
->listbox
.percentages
[1] = 25;
1548 ccd
->listbox
->listbox
.percentages
[2] = 20;
1549 ccd
->listbox
->listbox
.percentages
[3] = 40;
1550 ctrl_columns(s
, 2, 67, 33);
1551 ccd
->editbox
= ctrl_editbox(s
, "Set to class", 't', 50,
1552 HELPCTX(selection_charclasses
),
1553 charclass_handler
, P(ccd
), P(NULL
));
1554 ccd
->editbox
->generic
.column
= 0;
1555 ccd
->button
= ctrl_pushbutton(s
, "Set", 's',
1556 HELPCTX(selection_charclasses
),
1557 charclass_handler
, P(ccd
));
1558 ccd
->button
->generic
.column
= 1;
1559 ctrl_columns(s
, 1, 100);
1562 * The Window/Colours panel.
1564 ctrl_settitle(b
, "Window/Colours", "Options controlling use of colours");
1566 s
= ctrl_getset(b
, "Window/Colours", "general",
1567 "General options for colour usage");
1568 ctrl_checkbox(s
, "Allow terminal to specify ANSI colours", 'i',
1569 HELPCTX(colours_ansi
),
1570 dlg_stdcheckbox_handler
, I(offsetof(Config
,ansi_colour
)));
1571 ctrl_checkbox(s
, "Allow terminal to use xterm 256-colour mode", '2',
1572 HELPCTX(colours_xterm256
), dlg_stdcheckbox_handler
,
1573 I(offsetof(Config
,xterm_256_colour
)));
1574 ctrl_checkbox(s
, "Bolded text is a different colour", 'b',
1575 HELPCTX(colours_bold
),
1576 dlg_stdcheckbox_handler
, I(offsetof(Config
,bold_colour
)));
1578 str
= dupprintf("Adjust the precise colours %s displays", appname
);
1579 s
= ctrl_getset(b
, "Window/Colours", "adjust", str
);
1581 ctrl_text(s
, "Select a colour from the list, and then click the"
1582 " Modify button to change its appearance.",
1583 HELPCTX(colours_config
));
1584 ctrl_columns(s
, 2, 67, 33);
1585 cd
= (struct colour_data
*)ctrl_alloc(b
, sizeof(struct colour_data
));
1586 cd
->listbox
= ctrl_listbox(s
, "Select a colour to adjust:", 'u',
1587 HELPCTX(colours_config
), colour_handler
, P(cd
));
1588 cd
->listbox
->generic
.column
= 0;
1589 cd
->listbox
->listbox
.height
= 7;
1590 c
= ctrl_text(s
, "RGB value:", HELPCTX(colours_config
));
1591 c
->generic
.column
= 1;
1592 cd
->redit
= ctrl_editbox(s
, "Red", 'r', 50, HELPCTX(colours_config
),
1593 colour_handler
, P(cd
), P(NULL
));
1594 cd
->redit
->generic
.column
= 1;
1595 cd
->gedit
= ctrl_editbox(s
, "Green", 'n', 50, HELPCTX(colours_config
),
1596 colour_handler
, P(cd
), P(NULL
));
1597 cd
->gedit
->generic
.column
= 1;
1598 cd
->bedit
= ctrl_editbox(s
, "Blue", 'e', 50, HELPCTX(colours_config
),
1599 colour_handler
, P(cd
), P(NULL
));
1600 cd
->bedit
->generic
.column
= 1;
1601 cd
->button
= ctrl_pushbutton(s
, "Modify", 'm', HELPCTX(colours_config
),
1602 colour_handler
, P(cd
));
1603 cd
->button
->generic
.column
= 1;
1604 ctrl_columns(s
, 1, 100);
1607 * The Connection panel. This doesn't show up if we're in a
1608 * non-network utility such as pterm. We tell this by being
1609 * passed a protocol < 0.
1611 if (protocol
>= 0) {
1612 ctrl_settitle(b
, "Connection", "Options controlling the connection");
1614 s
= ctrl_getset(b
, "Connection", "keepalive",
1615 "Sending of null packets to keep session active");
1616 ctrl_editbox(s
, "Seconds between keepalives (0 to turn off)", 'k', 20,
1617 HELPCTX(connection_keepalive
),
1618 dlg_stdeditbox_handler
, I(offsetof(Config
,ping_interval
)),
1622 s
= ctrl_getset(b
, "Connection", "tcp",
1623 "Low-level TCP connection options");
1624 ctrl_checkbox(s
, "Disable Nagle's algorithm (TCP_NODELAY option)",
1625 'n', HELPCTX(connection_nodelay
),
1626 dlg_stdcheckbox_handler
,
1627 I(offsetof(Config
,tcp_nodelay
)));
1628 ctrl_checkbox(s
, "Enable TCP keepalives (SO_KEEPALIVE option)",
1629 'p', HELPCTX(connection_tcpkeepalive
),
1630 dlg_stdcheckbox_handler
,
1631 I(offsetof(Config
,tcp_keepalives
)));
1633 s
= ctrl_getset(b
, "Connection", "ipversion",
1634 "Internet protocol version");
1635 ctrl_radiobuttons(s
, NULL
, NO_SHORTCUT
, 3,
1636 HELPCTX(connection_ipversion
),
1637 dlg_stdradiobutton_handler
,
1638 I(offsetof(Config
, addressfamily
)),
1639 "Auto", 'u', I(ADDRTYPE_UNSPEC
),
1640 "IPv4", '4', I(ADDRTYPE_IPV4
),
1641 "IPv6", '6', I(ADDRTYPE_IPV6
),
1647 * A sub-panel Connection/Data, containing options that
1648 * decide on data to send to the server.
1651 ctrl_settitle(b
, "Connection/Data", "Data to send to the server");
1653 s
= ctrl_getset(b
, "Connection/Data", "login",
1655 ctrl_editbox(s
, "Auto-login username", 'u', 50,
1656 HELPCTX(connection_username
),
1657 dlg_stdeditbox_handler
, I(offsetof(Config
,username
)),
1658 I(sizeof(((Config
*)0)->username
)));
1660 s
= ctrl_getset(b
, "Connection/Data", "term",
1661 "Terminal details");
1662 ctrl_editbox(s
, "Terminal-type string", 't', 50,
1663 HELPCTX(connection_termtype
),
1664 dlg_stdeditbox_handler
, I(offsetof(Config
,termtype
)),
1665 I(sizeof(((Config
*)0)->termtype
)));
1666 ctrl_editbox(s
, "Terminal speeds", 's', 50,
1667 HELPCTX(connection_termspeed
),
1668 dlg_stdeditbox_handler
, I(offsetof(Config
,termspeed
)),
1669 I(sizeof(((Config
*)0)->termspeed
)));
1671 s
= ctrl_getset(b
, "Connection/Data", "env",
1672 "Environment variables");
1673 ctrl_columns(s
, 2, 80, 20);
1674 ed
= (struct environ_data
*)
1675 ctrl_alloc(b
, sizeof(struct environ_data
));
1676 ed
->varbox
= ctrl_editbox(s
, "Variable", 'v', 60,
1677 HELPCTX(telnet_environ
),
1678 environ_handler
, P(ed
), P(NULL
));
1679 ed
->varbox
->generic
.column
= 0;
1680 ed
->valbox
= ctrl_editbox(s
, "Value", 'l', 60,
1681 HELPCTX(telnet_environ
),
1682 environ_handler
, P(ed
), P(NULL
));
1683 ed
->valbox
->generic
.column
= 0;
1684 ed
->addbutton
= ctrl_pushbutton(s
, "Add", 'd',
1685 HELPCTX(telnet_environ
),
1686 environ_handler
, P(ed
));
1687 ed
->addbutton
->generic
.column
= 1;
1688 ed
->rembutton
= ctrl_pushbutton(s
, "Remove", 'r',
1689 HELPCTX(telnet_environ
),
1690 environ_handler
, P(ed
));
1691 ed
->rembutton
->generic
.column
= 1;
1692 ctrl_columns(s
, 1, 100);
1693 ed
->listbox
= ctrl_listbox(s
, NULL
, NO_SHORTCUT
,
1694 HELPCTX(telnet_environ
),
1695 environ_handler
, P(ed
));
1696 ed
->listbox
->listbox
.height
= 3;
1697 ed
->listbox
->listbox
.ncols
= 2;
1698 ed
->listbox
->listbox
.percentages
= snewn(2, int);
1699 ed
->listbox
->listbox
.percentages
[0] = 30;
1700 ed
->listbox
->listbox
.percentages
[1] = 70;
1707 * The Connection/Proxy panel.
1709 ctrl_settitle(b
, "Connection/Proxy",
1710 "Options controlling proxy usage");
1712 s
= ctrl_getset(b
, "Connection/Proxy", "basics", NULL
);
1713 ctrl_radiobuttons(s
, "Proxy type:", 't', 3,
1714 HELPCTX(proxy_type
),
1715 dlg_stdradiobutton_handler
,
1716 I(offsetof(Config
, proxy_type
)),
1717 "None", I(PROXY_NONE
),
1718 "SOCKS 4", I(PROXY_SOCKS4
),
1719 "SOCKS 5", I(PROXY_SOCKS5
),
1720 "HTTP", I(PROXY_HTTP
),
1721 "Telnet", I(PROXY_TELNET
),
1723 ctrl_columns(s
, 2, 80, 20);
1724 c
= ctrl_editbox(s
, "Proxy hostname", 'y', 100,
1725 HELPCTX(proxy_main
),
1726 dlg_stdeditbox_handler
,
1727 I(offsetof(Config
,proxy_host
)),
1728 I(sizeof(((Config
*)0)->proxy_host
)));
1729 c
->generic
.column
= 0;
1730 c
= ctrl_editbox(s
, "Port", 'p', 100,
1731 HELPCTX(proxy_main
),
1732 dlg_stdeditbox_handler
,
1733 I(offsetof(Config
,proxy_port
)),
1735 c
->generic
.column
= 1;
1736 ctrl_columns(s
, 1, 100);
1737 ctrl_editbox(s
, "Exclude Hosts/IPs", 'e', 100,
1738 HELPCTX(proxy_exclude
),
1739 dlg_stdeditbox_handler
,
1740 I(offsetof(Config
,proxy_exclude_list
)),
1741 I(sizeof(((Config
*)0)->proxy_exclude_list
)));
1742 ctrl_checkbox(s
, "Consider proxying local host connections", 'x',
1743 HELPCTX(proxy_exclude
),
1744 dlg_stdcheckbox_handler
,
1745 I(offsetof(Config
,even_proxy_localhost
)));
1746 ctrl_radiobuttons(s
, "Do DNS name lookup at proxy end:", 'd', 3,
1748 dlg_stdradiobutton_handler
,
1749 I(offsetof(Config
, proxy_dns
)),
1752 "Yes", I(FORCE_ON
), NULL
);
1753 ctrl_editbox(s
, "Username", 'u', 60,
1754 HELPCTX(proxy_auth
),
1755 dlg_stdeditbox_handler
,
1756 I(offsetof(Config
,proxy_username
)),
1757 I(sizeof(((Config
*)0)->proxy_username
)));
1758 c
= ctrl_editbox(s
, "Password", 'w', 60,
1759 HELPCTX(proxy_auth
),
1760 dlg_stdeditbox_handler
,
1761 I(offsetof(Config
,proxy_password
)),
1762 I(sizeof(((Config
*)0)->proxy_password
)));
1763 c
->editbox
.password
= 1;
1764 ctrl_editbox(s
, "Telnet command", 'm', 100,
1765 HELPCTX(proxy_command
),
1766 dlg_stdeditbox_handler
,
1767 I(offsetof(Config
,proxy_telnet_command
)),
1768 I(sizeof(((Config
*)0)->proxy_telnet_command
)));
1772 * The Telnet panel exists in the base config box, and in a
1773 * mid-session reconfig box _if_ we're using Telnet.
1775 if (!midsession
|| protocol
== PROT_TELNET
) {
1777 * The Connection/Telnet panel.
1779 ctrl_settitle(b
, "Connection/Telnet",
1780 "Options controlling Telnet connections");
1782 s
= ctrl_getset(b
, "Connection/Telnet", "protocol",
1783 "Telnet protocol adjustments");
1786 ctrl_radiobuttons(s
, "Handling of OLD_ENVIRON ambiguity:",
1788 HELPCTX(telnet_oldenviron
),
1789 dlg_stdradiobutton_handler
,
1790 I(offsetof(Config
, rfc_environ
)),
1791 "BSD (commonplace)", 'b', I(0),
1792 "RFC 1408 (unusual)", 'f', I(1), NULL
);
1793 ctrl_radiobuttons(s
, "Telnet negotiation mode:", 't', 2,
1794 HELPCTX(telnet_passive
),
1795 dlg_stdradiobutton_handler
,
1796 I(offsetof(Config
, passive_telnet
)),
1797 "Passive", I(1), "Active", I(0), NULL
);
1799 ctrl_checkbox(s
, "Keyboard sends Telnet special commands", 'k',
1800 HELPCTX(telnet_specialkeys
),
1801 dlg_stdcheckbox_handler
,
1802 I(offsetof(Config
,telnet_keyboard
)));
1803 ctrl_checkbox(s
, "Return key sends Telnet New Line instead of ^M",
1804 'm', HELPCTX(telnet_newline
),
1805 dlg_stdcheckbox_handler
,
1806 I(offsetof(Config
,telnet_newline
)));
1812 * The Connection/Rlogin panel.
1814 ctrl_settitle(b
, "Connection/Rlogin",
1815 "Options controlling Rlogin connections");
1817 s
= ctrl_getset(b
, "Connection/Rlogin", "data",
1818 "Data to send to the server");
1819 ctrl_editbox(s
, "Local username:", 'l', 50,
1820 HELPCTX(rlogin_localuser
),
1821 dlg_stdeditbox_handler
, I(offsetof(Config
,localusername
)),
1822 I(sizeof(((Config
*)0)->localusername
)));
1827 * All the SSH stuff is omitted in PuTTYtel, or in a reconfig
1828 * when we're not doing SSH.
1831 if (backends
[3].name
!= NULL
&& (!midsession
|| protocol
== PROT_SSH
)) {
1834 * The Connection/SSH panel.
1836 ctrl_settitle(b
, "Connection/SSH",
1837 "Options controlling SSH connections");
1839 if (midsession
&& protcfginfo
== 1) {
1840 s
= ctrl_getset(b
, "Connection/SSH", "disclaimer", NULL
);
1841 ctrl_text(s
, "Nothing on this panel may be reconfigured in mid-"
1842 "session; it is only here so that sub-panels of it can "
1843 "exist without looking strange.", HELPCTX(no_help
));
1848 s
= ctrl_getset(b
, "Connection/SSH", "data",
1849 "Data to send to the server");
1850 ctrl_editbox(s
, "Remote command:", 'r', 100,
1851 HELPCTX(ssh_command
),
1852 dlg_stdeditbox_handler
, I(offsetof(Config
,remote_cmd
)),
1853 I(sizeof(((Config
*)0)->remote_cmd
)));
1855 s
= ctrl_getset(b
, "Connection/SSH", "protocol", "Protocol options");
1856 ctrl_checkbox(s
, "Don't start a shell or command at all", 'n',
1857 HELPCTX(ssh_noshell
),
1858 dlg_stdcheckbox_handler
,
1859 I(offsetof(Config
,ssh_no_shell
)));
1862 if (!midsession
|| protcfginfo
!= 1) {
1863 s
= ctrl_getset(b
, "Connection/SSH", "protocol", "Protocol options");
1865 ctrl_checkbox(s
, "Enable compression", 'e',
1866 HELPCTX(ssh_compress
),
1867 dlg_stdcheckbox_handler
,
1868 I(offsetof(Config
,compression
)));
1872 s
= ctrl_getset(b
, "Connection/SSH", "protocol", "Protocol options");
1874 ctrl_radiobuttons(s
, "Preferred SSH protocol version:", NO_SHORTCUT
, 4,
1875 HELPCTX(ssh_protocol
),
1876 dlg_stdradiobutton_handler
,
1877 I(offsetof(Config
, sshprot
)),
1878 "1 only", 'l', I(0),
1881 "2 only", 'y', I(3), NULL
);
1884 if (!midsession
|| protcfginfo
!= 1) {
1885 s
= ctrl_getset(b
, "Connection/SSH", "encryption", "Encryption options");
1886 c
= ctrl_draglist(s
, "Encryption cipher selection policy:", 's',
1887 HELPCTX(ssh_ciphers
),
1888 cipherlist_handler
, P(NULL
));
1889 c
->listbox
.height
= 6;
1891 ctrl_checkbox(s
, "Enable legacy use of single-DES in SSH-2", 'i',
1892 HELPCTX(ssh_ciphers
),
1893 dlg_stdcheckbox_handler
,
1894 I(offsetof(Config
,ssh2_des_cbc
)));
1898 * The Connection/SSH/Kex panel. (Owing to repeat key
1899 * exchange, this is all meaningful in mid-session _if_
1900 * we're using SSH-2 or haven't decided yet.)
1902 if (protcfginfo
!= 1) {
1903 ctrl_settitle(b
, "Connection/SSH/Kex",
1904 "Options controlling SSH key exchange");
1906 s
= ctrl_getset(b
, "Connection/SSH/Kex", "main",
1907 "Key exchange algorithm options");
1908 c
= ctrl_draglist(s
, "Algorithm selection policy:", 's',
1909 HELPCTX(ssh_kexlist
),
1910 kexlist_handler
, P(NULL
));
1911 c
->listbox
.height
= 5;
1913 s
= ctrl_getset(b
, "Connection/SSH/Kex", "repeat",
1914 "Options controlling key re-exchange");
1916 ctrl_editbox(s
, "Max minutes before rekey (0 for no limit)", 't', 20,
1917 HELPCTX(ssh_kex_repeat
),
1918 dlg_stdeditbox_handler
,
1919 I(offsetof(Config
,ssh_rekey_time
)),
1921 ctrl_editbox(s
, "Max data before rekey (0 for no limit)", 'x', 20,
1922 HELPCTX(ssh_kex_repeat
),
1923 dlg_stdeditbox_handler
,
1924 I(offsetof(Config
,ssh_rekey_data
)),
1926 ctrl_text(s
, "(Use 1M for 1 megabyte, 1G for 1 gigabyte etc)",
1927 HELPCTX(ssh_kex_repeat
));
1933 * The Connection/SSH/Auth panel.
1935 ctrl_settitle(b
, "Connection/SSH/Auth",
1936 "Options controlling SSH authentication");
1938 s
= ctrl_getset(b
, "Connection/SSH/Auth", "main", NULL
);
1939 ctrl_checkbox(s
, "Bypass authentication entirely (SSH-2 only)", 'b',
1940 HELPCTX(ssh_auth_bypass
),
1941 dlg_stdcheckbox_handler
,
1942 I(offsetof(Config
,ssh_no_userauth
)));
1944 s
= ctrl_getset(b
, "Connection/SSH/Auth", "methods",
1945 "Authentication methods");
1946 ctrl_checkbox(s
, "Attempt authentication using Pageant", 'p',
1947 HELPCTX(ssh_auth_pageant
),
1948 dlg_stdcheckbox_handler
,
1949 I(offsetof(Config
,tryagent
)));
1950 ctrl_checkbox(s
, "Attempt TIS or CryptoCard auth (SSH-1)", 'm',
1951 HELPCTX(ssh_auth_tis
),
1952 dlg_stdcheckbox_handler
,
1953 I(offsetof(Config
,try_tis_auth
)));
1954 ctrl_checkbox(s
, "Attempt \"keyboard-interactive\" auth (SSH-2)",
1955 'i', HELPCTX(ssh_auth_ki
),
1956 dlg_stdcheckbox_handler
,
1957 I(offsetof(Config
,try_ki_auth
)));
1959 s
= ctrl_getset(b
, "Connection/SSH/Auth", "params",
1960 "Authentication parameters");
1961 ctrl_checkbox(s
, "Allow agent forwarding", 'f',
1962 HELPCTX(ssh_auth_agentfwd
),
1963 dlg_stdcheckbox_handler
, I(offsetof(Config
,agentfwd
)));
1964 ctrl_checkbox(s
, "Allow attempted changes of username in SSH-2", 'u',
1965 HELPCTX(ssh_auth_changeuser
),
1966 dlg_stdcheckbox_handler
,
1967 I(offsetof(Config
,change_username
)));
1968 ctrl_filesel(s
, "Private key file for authentication:", 'k',
1969 FILTER_KEY_FILES
, FALSE
, "Select private key file",
1970 HELPCTX(ssh_auth_privkey
),
1971 dlg_stdfilesel_handler
, I(offsetof(Config
, keyfile
)));
1976 * The Connection/SSH/TTY panel.
1978 ctrl_settitle(b
, "Connection/SSH/TTY", "Remote terminal settings");
1980 s
= ctrl_getset(b
, "Connection/SSH/TTY", "sshtty", NULL
);
1981 ctrl_checkbox(s
, "Don't allocate a pseudo-terminal", 'p',
1983 dlg_stdcheckbox_handler
,
1984 I(offsetof(Config
,nopty
)));
1986 s
= ctrl_getset(b
, "Connection/SSH/TTY", "ttymodes",
1988 td
= (struct ttymodes_data
*)
1989 ctrl_alloc(b
, sizeof(struct ttymodes_data
));
1990 ctrl_columns(s
, 2, 75, 25);
1991 c
= ctrl_text(s
, "Terminal modes to send:", HELPCTX(ssh_ttymodes
));
1992 c
->generic
.column
= 0;
1993 td
->rembutton
= ctrl_pushbutton(s
, "Remove", 'r',
1994 HELPCTX(ssh_ttymodes
),
1995 ttymodes_handler
, P(td
));
1996 td
->rembutton
->generic
.column
= 1;
1997 td
->rembutton
->generic
.tabdelay
= 1;
1998 ctrl_columns(s
, 1, 100);
1999 td
->listbox
= ctrl_listbox(s
, NULL
, NO_SHORTCUT
,
2000 HELPCTX(ssh_ttymodes
),
2001 ttymodes_handler
, P(td
));
2002 td
->listbox
->listbox
.multisel
= 1;
2003 td
->listbox
->listbox
.height
= 4;
2004 td
->listbox
->listbox
.ncols
= 2;
2005 td
->listbox
->listbox
.percentages
= snewn(2, int);
2006 td
->listbox
->listbox
.percentages
[0] = 40;
2007 td
->listbox
->listbox
.percentages
[1] = 60;
2008 ctrl_tabdelay(s
, td
->rembutton
);
2009 ctrl_columns(s
, 2, 75, 25);
2010 td
->modelist
= ctrl_droplist(s
, "Mode:", 'm', 67,
2011 HELPCTX(ssh_ttymodes
),
2012 ttymodes_handler
, P(td
));
2013 td
->modelist
->generic
.column
= 0;
2014 td
->addbutton
= ctrl_pushbutton(s
, "Add", 'd',
2015 HELPCTX(ssh_ttymodes
),
2016 ttymodes_handler
, P(td
));
2017 td
->addbutton
->generic
.column
= 1;
2018 td
->addbutton
->generic
.tabdelay
= 1;
2019 ctrl_columns(s
, 1, 100); /* column break */
2020 /* Bit of a hack to get the value radio buttons and
2021 * edit-box on the same row. */
2022 ctrl_columns(s
, 3, 25, 50, 25);
2023 c
= ctrl_text(s
, "Value:", HELPCTX(ssh_ttymodes
));
2024 c
->generic
.column
= 0;
2025 td
->valradio
= ctrl_radiobuttons(s
, NULL
, NO_SHORTCUT
, 2,
2026 HELPCTX(ssh_ttymodes
),
2027 ttymodes_handler
, P(td
),
2028 "Auto", NO_SHORTCUT
, P(NULL
),
2029 "This:", NO_SHORTCUT
, P(NULL
),
2031 td
->valradio
->generic
.column
= 1;
2032 td
->valbox
= ctrl_editbox(s
, NULL
, NO_SHORTCUT
, 100,
2033 HELPCTX(ssh_ttymodes
),
2034 ttymodes_handler
, P(td
), P(NULL
));
2035 td
->valbox
->generic
.column
= 2;
2036 ctrl_tabdelay(s
, td
->addbutton
);
2042 * The Connection/SSH/X11 panel.
2044 ctrl_settitle(b
, "Connection/SSH/X11",
2045 "Options controlling SSH X11 forwarding");
2047 s
= ctrl_getset(b
, "Connection/SSH/X11", "x11", "X11 forwarding");
2048 ctrl_checkbox(s
, "Enable X11 forwarding", 'e',
2049 HELPCTX(ssh_tunnels_x11
),
2050 dlg_stdcheckbox_handler
,I(offsetof(Config
,x11_forward
)));
2051 ctrl_editbox(s
, "X display location", 'x', 50,
2052 HELPCTX(ssh_tunnels_x11
),
2053 dlg_stdeditbox_handler
, I(offsetof(Config
,x11_display
)),
2054 I(sizeof(((Config
*)0)->x11_display
)));
2055 ctrl_radiobuttons(s
, "Remote X11 authentication protocol", 'u', 2,
2056 HELPCTX(ssh_tunnels_x11auth
),
2057 dlg_stdradiobutton_handler
,
2058 I(offsetof(Config
, x11_auth
)),
2059 "MIT-Magic-Cookie-1", I(X11_MIT
),
2060 "XDM-Authorization-1", I(X11_XDM
), NULL
);
2064 * The Tunnels panel _is_ still available in mid-session.
2066 ctrl_settitle(b
, "Connection/SSH/Tunnels",
2067 "Options controlling SSH port forwarding");
2069 s
= ctrl_getset(b
, "Connection/SSH/Tunnels", "portfwd",
2071 ctrl_checkbox(s
, "Local ports accept connections from other hosts",'t',
2072 HELPCTX(ssh_tunnels_portfwd_localhost
),
2073 dlg_stdcheckbox_handler
,
2074 I(offsetof(Config
,lport_acceptall
)));
2075 ctrl_checkbox(s
, "Remote ports do the same (SSH-2 only)", 'p',
2076 HELPCTX(ssh_tunnels_portfwd_localhost
),
2077 dlg_stdcheckbox_handler
,
2078 I(offsetof(Config
,rport_acceptall
)));
2080 ctrl_columns(s
, 3, 55, 20, 25);
2081 c
= ctrl_text(s
, "Forwarded ports:", HELPCTX(ssh_tunnels_portfwd
));
2082 c
->generic
.column
= COLUMN_FIELD(0,2);
2083 /* You want to select from the list, _then_ hit Remove. So tab order
2084 * should be that way round. */
2085 pfd
= (struct portfwd_data
*)ctrl_alloc(b
,sizeof(struct portfwd_data
));
2086 pfd
->rembutton
= ctrl_pushbutton(s
, "Remove", 'r',
2087 HELPCTX(ssh_tunnels_portfwd
),
2088 portfwd_handler
, P(pfd
));
2089 pfd
->rembutton
->generic
.column
= 2;
2090 pfd
->rembutton
->generic
.tabdelay
= 1;
2091 pfd
->listbox
= ctrl_listbox(s
, NULL
, NO_SHORTCUT
,
2092 HELPCTX(ssh_tunnels_portfwd
),
2093 portfwd_handler
, P(pfd
));
2094 pfd
->listbox
->listbox
.height
= 3;
2095 pfd
->listbox
->listbox
.ncols
= 2;
2096 pfd
->listbox
->listbox
.percentages
= snewn(2, int);
2097 pfd
->listbox
->listbox
.percentages
[0] = 20;
2098 pfd
->listbox
->listbox
.percentages
[1] = 80;
2099 ctrl_tabdelay(s
, pfd
->rembutton
);
2100 ctrl_text(s
, "Add new forwarded port:", HELPCTX(ssh_tunnels_portfwd
));
2101 /* You want to enter source, destination and type, _then_ hit Add.
2102 * Again, we adjust the tab order to reflect this. */
2103 pfd
->addbutton
= ctrl_pushbutton(s
, "Add", 'd',
2104 HELPCTX(ssh_tunnels_portfwd
),
2105 portfwd_handler
, P(pfd
));
2106 pfd
->addbutton
->generic
.column
= 2;
2107 pfd
->addbutton
->generic
.tabdelay
= 1;
2108 pfd
->sourcebox
= ctrl_editbox(s
, "Source port", 's', 40,
2109 HELPCTX(ssh_tunnels_portfwd
),
2110 portfwd_handler
, P(pfd
), P(NULL
));
2111 pfd
->sourcebox
->generic
.column
= 0;
2112 pfd
->destbox
= ctrl_editbox(s
, "Destination", 'i', 67,
2113 HELPCTX(ssh_tunnels_portfwd
),
2114 portfwd_handler
, P(pfd
), P(NULL
));
2115 pfd
->direction
= ctrl_radiobuttons(s
, NULL
, NO_SHORTCUT
, 3,
2116 HELPCTX(ssh_tunnels_portfwd
),
2117 portfwd_handler
, P(pfd
),
2118 "Local", 'l', P(NULL
),
2119 "Remote", 'm', P(NULL
),
2120 "Dynamic", 'y', P(NULL
),
2123 pfd
->addressfamily
=
2124 ctrl_radiobuttons(s
, NULL
, NO_SHORTCUT
, 3,
2125 HELPCTX(ssh_tunnels_portfwd_ipversion
),
2126 portfwd_handler
, P(pfd
),
2127 "Auto", 'u', I(ADDRTYPE_UNSPEC
),
2128 "IPv4", '4', I(ADDRTYPE_IPV4
),
2129 "IPv6", '6', I(ADDRTYPE_IPV6
),
2132 ctrl_tabdelay(s
, pfd
->addbutton
);
2133 ctrl_columns(s
, 1, 100);
2137 * The Connection/SSH/Bugs panel.
2139 ctrl_settitle(b
, "Connection/SSH/Bugs",
2140 "Workarounds for SSH server bugs");
2142 s
= ctrl_getset(b
, "Connection/SSH/Bugs", "main",
2143 "Detection of known bugs in SSH servers");
2144 ctrl_droplist(s
, "Chokes on SSH-1 ignore messages", 'i', 20,
2145 HELPCTX(ssh_bugs_ignore1
),
2146 sshbug_handler
, I(offsetof(Config
,sshbug_ignore1
)));
2147 ctrl_droplist(s
, "Refuses all SSH-1 password camouflage", 's', 20,
2148 HELPCTX(ssh_bugs_plainpw1
),
2149 sshbug_handler
, I(offsetof(Config
,sshbug_plainpw1
)));
2150 ctrl_droplist(s
, "Chokes on SSH-1 RSA authentication", 'r', 20,
2151 HELPCTX(ssh_bugs_rsa1
),
2152 sshbug_handler
, I(offsetof(Config
,sshbug_rsa1
)));
2153 ctrl_droplist(s
, "Miscomputes SSH-2 HMAC keys", 'm', 20,
2154 HELPCTX(ssh_bugs_hmac2
),
2155 sshbug_handler
, I(offsetof(Config
,sshbug_hmac2
)));
2156 ctrl_droplist(s
, "Miscomputes SSH-2 encryption keys", 'e', 20,
2157 HELPCTX(ssh_bugs_derivekey2
),
2158 sshbug_handler
, I(offsetof(Config
,sshbug_derivekey2
)));
2159 ctrl_droplist(s
, "Requires padding on SSH-2 RSA signatures", 'p', 20,
2160 HELPCTX(ssh_bugs_rsapad2
),
2161 sshbug_handler
, I(offsetof(Config
,sshbug_rsapad2
)));
2162 ctrl_droplist(s
, "Misuses the session ID in SSH-2 PK auth", 'n', 20,
2163 HELPCTX(ssh_bugs_pksessid2
),
2164 sshbug_handler
, I(offsetof(Config
,sshbug_pksessid2
)));
2165 ctrl_droplist(s
, "Handles SSH-2 key re-exchange badly", 'k', 20,
2166 HELPCTX(ssh_bugs_rekey2
),
2167 sshbug_handler
, I(offsetof(Config
,sshbug_rekey2
)));