Readjust checklist, because actually the section on updating the
[u/mdw/putty] / config.c
CommitLineData
fe8abbf4 1/*
2 * config.c - the platform-independent parts of the PuTTY
3 * configuration box.
4 */
5
6#include <assert.h>
7#include <stdlib.h>
8
9#include "putty.h"
10#include "dialog.h"
11#include "storage.h"
12
13#define PRINTER_DISABLED_STRING "None (printing disabled)"
14
7374c779 15#define HOST_BOX_TITLE "Host Name (or IP address)"
16#define PORT_BOX_TITLE "Port"
17
18static void config_host_handler(union control *ctrl, void *dlg,
19 void *data, int event)
20{
21 Config *cfg = (Config *)data;
22
23 /*
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.
27 */
28 if (event == EVENT_REFRESH) {
29 if (cfg->protocol == PROT_SERIAL) {
30 /*
31 * This label text is carefully chosen to contain an n,
32 * since that's the shortcut for the host name control.
33 */
34 dlg_label_change(ctrl, dlg, "Serial line");
35 dlg_editbox_set(ctrl, dlg, cfg->serline);
36 } else {
37 dlg_label_change(ctrl, dlg, HOST_BOX_TITLE);
38 dlg_editbox_set(ctrl, dlg, cfg->host);
39 }
40 } else if (event == EVENT_VALCHANGE) {
41 if (cfg->protocol == PROT_SERIAL)
42 dlg_editbox_get(ctrl, dlg, cfg->serline, lenof(cfg->serline));
43 else
44 dlg_editbox_get(ctrl, dlg, cfg->host, lenof(cfg->host));
45 }
46}
47
48static void config_port_handler(union control *ctrl, void *dlg,
49 void *data, int event)
50{
51 Config *cfg = (Config *)data;
52 char buf[80];
53
54 /*
a28d45e3 55 * This function works similarly to the standard edit box handler,
7374c779 56 * only it has to choose the control's label and text from two
57 * different places depending on the protocol.
58 */
59 if (event == EVENT_REFRESH) {
60 if (cfg->protocol == PROT_SERIAL) {
61 /*
62 * This label text is carefully chosen to contain a p,
63 * since that's the shortcut for the port control.
64 */
65 dlg_label_change(ctrl, dlg, "Speed");
66 sprintf(buf, "%d", cfg->serspeed);
67 } else {
68 dlg_label_change(ctrl, dlg, PORT_BOX_TITLE);
a28d45e3 69 if (cfg->port != 0)
70 sprintf(buf, "%d", cfg->port);
71 else
72 /* Display an (invalid) port of 0 as blank */
73 buf[0] = '\0';
7374c779 74 }
75 dlg_editbox_set(ctrl, dlg, buf);
76 } else if (event == EVENT_VALCHANGE) {
77 dlg_editbox_get(ctrl, dlg, buf, lenof(buf));
78 if (cfg->protocol == PROT_SERIAL)
79 cfg->serspeed = atoi(buf);
80 else
81 cfg->port = atoi(buf);
82 }
83}
84
85struct hostport {
86 union control *host, *port;
87};
88
89/*
90 * We export this function so that platform-specific config
91 * routines can use it to conveniently identify the protocol radio
92 * buttons in order to add to them.
93 */
94void config_protocolbuttons_handler(union control *ctrl, void *dlg,
fe8abbf4 95 void *data, int event)
96{
a4451dd1 97 int button;
fe8abbf4 98 Config *cfg = (Config *)data;
7374c779 99 struct hostport *hp = (struct hostport *)ctrl->radio.context.p;
100
fe8abbf4 101 /*
102 * This function works just like the standard radio-button
103 * handler, except that it also has to change the setting of
7374c779 104 * the port box, and refresh both host and port boxes when. We
105 * expect the context parameter to point at a hostport
106 * structure giving the `union control's for both.
fe8abbf4 107 */
108 if (event == EVENT_REFRESH) {
109 for (button = 0; button < ctrl->radio.nbuttons; button++)
110 if (cfg->protocol == ctrl->radio.buttondata[button].i)
111 break;
112 /* We expected that `break' to happen, in all circumstances. */
113 assert(button < ctrl->radio.nbuttons);
114 dlg_radiobutton_set(ctrl, dlg, button);
115 } else if (event == EVENT_VALCHANGE) {
116 int oldproto = cfg->protocol;
117 button = dlg_radiobutton_get(ctrl, dlg);
118 assert(button >= 0 && button < ctrl->radio.nbuttons);
119 cfg->protocol = ctrl->radio.buttondata[button].i;
120 if (oldproto != cfg->protocol) {
a4451dd1 121 Backend *ob = backend_from_proto(oldproto);
122 Backend *nb = backend_from_proto(cfg->protocol);
123 assert(ob);
124 assert(nb);
a28d45e3 125 /* Iff the user hasn't changed the port from the old protocol's
126 * default, update it with the new protocol's default.
127 * (This includes a "default" of 0, implying that there is no
128 * sensible default for that protocol; in this case it's
129 * displayed as a blank.)
130 * This helps with the common case of tabbing through the
131 * controls in order and setting a non-default port before
132 * getting to the protocol; we want that non-default port
133 * to be preserved. */
134 if (cfg->port == ob->default_port)
a4451dd1 135 cfg->port = nb->default_port;
fe8abbf4 136 }
7374c779 137 dlg_refresh(hp->host, dlg);
138 dlg_refresh(hp->port, dlg);
fe8abbf4 139 }
140}
141
17556692 142static void loggingbuttons_handler(union control *ctrl, void *dlg,
143 void *data, int event)
144{
145 int button;
146 Config *cfg = (Config *)data;
147 /* This function works just like the standard radio-button handler,
148 * but it has to fall back to "no logging" in situations where the
149 * configured logging type isn't applicable.
150 */
151 if (event == EVENT_REFRESH) {
152 for (button = 0; button < ctrl->radio.nbuttons; button++)
153 if (cfg->logtype == ctrl->radio.buttondata[button].i)
154 break;
155
156 /* We fell off the end, so we lack the configured logging type */
157 if (button == ctrl->radio.nbuttons) {
158 button=0;
159 cfg->logtype=LGTYP_NONE;
160 }
161 dlg_radiobutton_set(ctrl, dlg, button);
162 } else if (event == EVENT_VALCHANGE) {
163 button = dlg_radiobutton_get(ctrl, dlg);
164 assert(button >= 0 && button < ctrl->radio.nbuttons);
165 cfg->logtype = ctrl->radio.buttondata[button].i;
166 }
167}
168
fe8abbf4 169static void numeric_keypad_handler(union control *ctrl, void *dlg,
170 void *data, int event)
171{
172 int button;
173 Config *cfg = (Config *)data;
174 /*
175 * This function works much like the standard radio button
176 * handler, but it has to handle two fields in Config.
177 */
178 if (event == EVENT_REFRESH) {
179 if (cfg->nethack_keypad)
180 button = 2;
181 else if (cfg->app_keypad)
182 button = 1;
183 else
184 button = 0;
185 assert(button < ctrl->radio.nbuttons);
186 dlg_radiobutton_set(ctrl, dlg, button);
187 } else if (event == EVENT_VALCHANGE) {
188 button = dlg_radiobutton_get(ctrl, dlg);
189 assert(button >= 0 && button < ctrl->radio.nbuttons);
190 if (button == 2) {
191 cfg->app_keypad = FALSE;
192 cfg->nethack_keypad = TRUE;
193 } else {
194 cfg->app_keypad = (button != 0);
195 cfg->nethack_keypad = FALSE;
196 }
197 }
198}
199
200static void cipherlist_handler(union control *ctrl, void *dlg,
201 void *data, int event)
202{
203 Config *cfg = (Config *)data;
204 if (event == EVENT_REFRESH) {
205 int i;
206
207 static const struct { char *s; int c; } ciphers[] = {
208 { "3DES", CIPHER_3DES },
209 { "Blowfish", CIPHER_BLOWFISH },
210 { "DES", CIPHER_DES },
2e85c969 211 { "AES (SSH-2 only)", CIPHER_AES },
a2add208 212 { "Arcfour (SSH-2 only)", CIPHER_ARCFOUR },
fe8abbf4 213 { "-- warn below here --", CIPHER_WARN }
214 };
215
216 /* Set up the "selected ciphers" box. */
217 /* (cipherlist assumed to contain all ciphers) */
218 dlg_update_start(ctrl, dlg);
219 dlg_listbox_clear(ctrl, dlg);
220 for (i = 0; i < CIPHER_MAX; i++) {
221 int c = cfg->ssh_cipherlist[i];
222 int j;
223 char *cstr = NULL;
224 for (j = 0; j < (sizeof ciphers) / (sizeof ciphers[0]); j++) {
225 if (ciphers[j].c == c) {
226 cstr = ciphers[j].s;
227 break;
228 }
229 }
4eaff8d4 230 dlg_listbox_addwithid(ctrl, dlg, cstr, c);
fe8abbf4 231 }
232 dlg_update_done(ctrl, dlg);
233
234 } else if (event == EVENT_VALCHANGE) {
235 int i;
236
237 /* Update array to match the list box. */
238 for (i=0; i < CIPHER_MAX; i++)
239 cfg->ssh_cipherlist[i] = dlg_listbox_getid(ctrl, dlg, i);
240
241 }
242}
243
b3d375b2 244#ifndef NO_GSSAPI
245static void gsslist_handler(union control *ctrl, void *dlg,
246 void *data, int event)
247{
248 Config *cfg = (Config *)data;
249 if (event == EVENT_REFRESH) {
250 int i;
251
252 dlg_update_start(ctrl, dlg);
253 dlg_listbox_clear(ctrl, dlg);
254 for (i = 0; i < ngsslibs; i++) {
255 int id = cfg->ssh_gsslist[i];
256 assert(id >= 0 && id < ngsslibs);
257 dlg_listbox_addwithid(ctrl, dlg, gsslibnames[id], id);
258 }
259 dlg_update_done(ctrl, dlg);
260
261 } else if (event == EVENT_VALCHANGE) {
262 int i;
263
264 /* Update array to match the list box. */
265 for (i=0; i < ngsslibs; i++)
266 cfg->ssh_gsslist[i] = dlg_listbox_getid(ctrl, dlg, i);
267 }
268}
269#endif
270
83e7d008 271static void kexlist_handler(union control *ctrl, void *dlg,
272 void *data, int event)
273{
274 Config *cfg = (Config *)data;
275 if (event == EVENT_REFRESH) {
276 int i;
277
278 static const struct { char *s; int k; } kexes[] = {
279 { "Diffie-Hellman group 1", KEX_DHGROUP1 },
280 { "Diffie-Hellman group 14", KEX_DHGROUP14 },
281 { "Diffie-Hellman group exchange", KEX_DHGEX },
fae1a71b 282 { "RSA-based key exchange", KEX_RSA },
83e7d008 283 { "-- warn below here --", KEX_WARN }
284 };
285
286 /* Set up the "kex preference" box. */
287 /* (kexlist assumed to contain all algorithms) */
288 dlg_update_start(ctrl, dlg);
289 dlg_listbox_clear(ctrl, dlg);
290 for (i = 0; i < KEX_MAX; i++) {
291 int k = cfg->ssh_kexlist[i];
292 int j;
293 char *kstr = NULL;
294 for (j = 0; j < (sizeof kexes) / (sizeof kexes[0]); j++) {
295 if (kexes[j].k == k) {
296 kstr = kexes[j].s;
297 break;
298 }
299 }
300 dlg_listbox_addwithid(ctrl, dlg, kstr, k);
301 }
302 dlg_update_done(ctrl, dlg);
303
304 } else if (event == EVENT_VALCHANGE) {
305 int i;
306
307 /* Update array to match the list box. */
308 for (i=0; i < KEX_MAX; i++)
309 cfg->ssh_kexlist[i] = dlg_listbox_getid(ctrl, dlg, i);
310
311 }
312}
313
fe8abbf4 314static void printerbox_handler(union control *ctrl, void *dlg,
315 void *data, int event)
316{
317 Config *cfg = (Config *)data;
318 if (event == EVENT_REFRESH) {
319 int nprinters, i;
320 printer_enum *pe;
321
322 dlg_update_start(ctrl, dlg);
0f915619 323 /*
324 * Some backends may wish to disable the drop-down list on
325 * this edit box. Be prepared for this.
326 */
327 if (ctrl->editbox.has_list) {
328 dlg_listbox_clear(ctrl, dlg);
329 dlg_listbox_add(ctrl, dlg, PRINTER_DISABLED_STRING);
330 pe = printer_start_enum(&nprinters);
331 for (i = 0; i < nprinters; i++)
332 dlg_listbox_add(ctrl, dlg, printer_get_name(pe, i));
333 printer_finish_enum(pe);
334 }
fe8abbf4 335 dlg_editbox_set(ctrl, dlg,
336 (*cfg->printer ? cfg->printer :
337 PRINTER_DISABLED_STRING));
338 dlg_update_done(ctrl, dlg);
339 } else if (event == EVENT_VALCHANGE) {
340 dlg_editbox_get(ctrl, dlg, cfg->printer, sizeof(cfg->printer));
341 if (!strcmp(cfg->printer, PRINTER_DISABLED_STRING))
342 *cfg->printer = '\0';
343 }
344}
345
346static void codepage_handler(union control *ctrl, void *dlg,
347 void *data, int event)
348{
349 Config *cfg = (Config *)data;
350 if (event == EVENT_REFRESH) {
351 int i;
759f419a 352 const char *cp, *thiscp;
fe8abbf4 353 dlg_update_start(ctrl, dlg);
759f419a 354 thiscp = cp_name(decode_codepage(cfg->line_codepage));
fe8abbf4 355 dlg_listbox_clear(ctrl, dlg);
356 for (i = 0; (cp = cp_enumerate(i)) != NULL; i++)
357 dlg_listbox_add(ctrl, dlg, cp);
759f419a 358 dlg_editbox_set(ctrl, dlg, thiscp);
359 strcpy(cfg->line_codepage, thiscp);
fe8abbf4 360 dlg_update_done(ctrl, dlg);
361 } else if (event == EVENT_VALCHANGE) {
362 dlg_editbox_get(ctrl, dlg, cfg->line_codepage,
363 sizeof(cfg->line_codepage));
364 strcpy(cfg->line_codepage,
365 cp_name(decode_codepage(cfg->line_codepage)));
366 }
367}
368
369static void sshbug_handler(union control *ctrl, void *dlg,
370 void *data, int event)
371{
372 if (event == EVENT_REFRESH) {
373 dlg_update_start(ctrl, dlg);
374 dlg_listbox_clear(ctrl, dlg);
4eaff8d4 375 dlg_listbox_addwithid(ctrl, dlg, "Auto", AUTO);
376 dlg_listbox_addwithid(ctrl, dlg, "Off", FORCE_OFF);
377 dlg_listbox_addwithid(ctrl, dlg, "On", FORCE_ON);
fe8abbf4 378 switch (*(int *)ATOFFSET(data, ctrl->listbox.context.i)) {
379 case AUTO: dlg_listbox_select(ctrl, dlg, 0); break;
380 case FORCE_OFF: dlg_listbox_select(ctrl, dlg, 1); break;
381 case FORCE_ON: dlg_listbox_select(ctrl, dlg, 2); break;
382 }
383 dlg_update_done(ctrl, dlg);
384 } else if (event == EVENT_SELCHANGE) {
385 int i = dlg_listbox_index(ctrl, dlg);
386 if (i < 0)
387 i = AUTO;
388 else
389 i = dlg_listbox_getid(ctrl, dlg, i);
390 *(int *)ATOFFSET(data, ctrl->listbox.context.i) = i;
391 }
392}
393
4e6d4091 394#define SAVEDSESSION_LEN 2048
395
fe8abbf4 396struct sessionsaver_data {
397 union control *editbox, *listbox, *loadbutton, *savebutton, *delbutton;
398 union control *okbutton, *cancelbutton;
12745e35 399 struct sesslist sesslist;
2e155f47 400 int midsession;
fe8abbf4 401};
402
403/*
404 * Helper function to load the session selected in the list box, if
405 * any, as this is done in more than one place below. Returns 0 for
406 * failure.
407 */
408static int load_selected_session(struct sessionsaver_data *ssd,
4e6d4091 409 char *savedsession,
95a9448f 410 void *dlg, Config *cfg, int *maybe_launch)
fe8abbf4 411{
412 int i = dlg_listbox_index(ssd->listbox, dlg);
413 int isdef;
414 if (i < 0) {
415 dlg_beep(dlg);
416 return 0;
417 }
12745e35 418 isdef = !strcmp(ssd->sesslist.sessions[i], "Default Settings");
47b5a6ae 419 load_settings(ssd->sesslist.sessions[i], cfg);
fe8abbf4 420 if (!isdef) {
12745e35 421 strncpy(savedsession, ssd->sesslist.sessions[i],
4e6d4091 422 SAVEDSESSION_LEN);
423 savedsession[SAVEDSESSION_LEN-1] = '\0';
95a9448f 424 if (maybe_launch)
425 *maybe_launch = TRUE;
fe8abbf4 426 } else {
4e6d4091 427 savedsession[0] = '\0';
95a9448f 428 if (maybe_launch)
429 *maybe_launch = FALSE;
fe8abbf4 430 }
431 dlg_refresh(NULL, dlg);
432 /* Restore the selection, which might have been clobbered by
433 * changing the value of the edit box. */
434 dlg_listbox_select(ssd->listbox, dlg, i);
435 return 1;
436}
437
438static void sessionsaver_handler(union control *ctrl, void *dlg,
439 void *data, int event)
440{
441 Config *cfg = (Config *)data;
442 struct sessionsaver_data *ssd =
443 (struct sessionsaver_data *)ctrl->generic.context.p;
4e6d4091 444 char *savedsession;
445
446 /*
447 * The first time we're called in a new dialog, we must
448 * allocate space to store the current contents of the saved
449 * session edit box (since it must persist even when we switch
450 * panels, but is not part of the Config).
451 */
56b9b9a7 452 if (!ssd->editbox) {
453 savedsession = NULL;
454 } else if (!dlg_get_privdata(ssd->editbox, dlg)) {
4e6d4091 455 savedsession = (char *)
456 dlg_alloc_privdata(ssd->editbox, dlg, SAVEDSESSION_LEN);
457 savedsession[0] = '\0';
458 } else {
459 savedsession = dlg_get_privdata(ssd->editbox, dlg);
460 }
fe8abbf4 461
462 if (event == EVENT_REFRESH) {
463 if (ctrl == ssd->editbox) {
4e6d4091 464 dlg_editbox_set(ctrl, dlg, savedsession);
fe8abbf4 465 } else if (ctrl == ssd->listbox) {
466 int i;
467 dlg_update_start(ctrl, dlg);
468 dlg_listbox_clear(ctrl, dlg);
12745e35 469 for (i = 0; i < ssd->sesslist.nsessions; i++)
470 dlg_listbox_add(ctrl, dlg, ssd->sesslist.sessions[i]);
fe8abbf4 471 dlg_update_done(ctrl, dlg);
472 }
473 } else if (event == EVENT_VALCHANGE) {
dcfd0728 474 int top, bottom, halfway, i;
fe8abbf4 475 if (ctrl == ssd->editbox) {
4e6d4091 476 dlg_editbox_get(ctrl, dlg, savedsession,
477 SAVEDSESSION_LEN);
dcfd0728 478 top = ssd->sesslist.nsessions;
479 bottom = -1;
480 while (top-bottom > 1) {
481 halfway = (top+bottom)/2;
482 i = strcmp(savedsession, ssd->sesslist.sessions[halfway]);
483 if (i <= 0 ) {
484 top = halfway;
485 } else {
486 bottom = halfway;
487 }
488 }
489 if (top == ssd->sesslist.nsessions) {
490 top -= 1;
491 }
492 dlg_listbox_select(ssd->listbox, dlg, top);
fe8abbf4 493 }
494 } else if (event == EVENT_ACTION) {
95a9448f 495 int mbl = FALSE;
2e155f47 496 if (!ssd->midsession &&
497 (ctrl == ssd->listbox ||
498 (ssd->loadbutton && ctrl == ssd->loadbutton))) {
fe8abbf4 499 /*
500 * The user has double-clicked a session, or hit Load.
501 * We must load the selected session, and then
502 * terminate the configuration dialog _if_ there was a
503 * double-click on the list box _and_ that session
504 * contains a hostname.
505 */
95a9448f 506 if (load_selected_session(ssd, savedsession, dlg, cfg, &mbl) &&
507 (mbl && ctrl == ssd->listbox && cfg_launchable(cfg))) {
fe8abbf4 508 dlg_end(dlg, 1); /* it's all over, and succeeded */
509 }
510 } else if (ctrl == ssd->savebutton) {
4e6d4091 511 int isdef = !strcmp(savedsession, "Default Settings");
512 if (!savedsession[0]) {
8b0cb5aa 513 int i = dlg_listbox_index(ssd->listbox, dlg);
fe8abbf4 514 if (i < 0) {
515 dlg_beep(dlg);
516 return;
517 }
12745e35 518 isdef = !strcmp(ssd->sesslist.sessions[i], "Default Settings");
fe8abbf4 519 if (!isdef) {
12745e35 520 strncpy(savedsession, ssd->sesslist.sessions[i],
4e6d4091 521 SAVEDSESSION_LEN);
522 savedsession[SAVEDSESSION_LEN-1] = '\0';
fe8abbf4 523 } else {
4e6d4091 524 savedsession[0] = '\0';
fe8abbf4 525 }
526 }
3f935d5b 527 {
47b5a6ae 528 char *errmsg = save_settings(savedsession, cfg);
3f935d5b 529 if (errmsg) {
530 dlg_error_msg(dlg, errmsg);
531 sfree(errmsg);
532 }
533 }
12745e35 534 get_sesslist(&ssd->sesslist, FALSE);
535 get_sesslist(&ssd->sesslist, TRUE);
fe8abbf4 536 dlg_refresh(ssd->editbox, dlg);
537 dlg_refresh(ssd->listbox, dlg);
2e155f47 538 } else if (!ssd->midsession &&
539 ssd->delbutton && ctrl == ssd->delbutton) {
6f87d111 540 int i = dlg_listbox_index(ssd->listbox, dlg);
fe8abbf4 541 if (i <= 0) {
542 dlg_beep(dlg);
543 } else {
12745e35 544 del_settings(ssd->sesslist.sessions[i]);
545 get_sesslist(&ssd->sesslist, FALSE);
546 get_sesslist(&ssd->sesslist, TRUE);
fe8abbf4 547 dlg_refresh(ssd->listbox, dlg);
548 }
549 } else if (ctrl == ssd->okbutton) {
2e155f47 550 if (ssd->midsession) {
56b9b9a7 551 /* In a mid-session Change Settings, Apply is always OK. */
552 dlg_end(dlg, 1);
553 return;
554 }
fe8abbf4 555 /*
556 * Annoying special case. If the `Open' button is
557 * pressed while no host name is currently set, _and_
558 * the session list previously had the focus, _and_
559 * there was a session selected in that which had a
560 * valid host name in it, then load it and go.
561 */
7374c779 562 if (dlg_last_focused(ctrl, dlg) == ssd->listbox &&
563 !cfg_launchable(cfg)) {
fe8abbf4 564 Config cfg2;
95a9448f 565 int mbl = FALSE;
566 if (!load_selected_session(ssd, savedsession, dlg,
567 &cfg2, &mbl)) {
fe8abbf4 568 dlg_beep(dlg);
569 return;
570 }
571 /* If at this point we have a valid session, go! */
95a9448f 572 if (mbl && cfg_launchable(&cfg2)) {
fe8abbf4 573 *cfg = cfg2; /* structure copy */
04c52f10 574 cfg->remote_cmd_ptr = NULL;
fe8abbf4 575 dlg_end(dlg, 1);
576 } else
577 dlg_beep(dlg);
431c0a12 578 return;
fe8abbf4 579 }
580
581 /*
582 * Otherwise, do the normal thing: if we have a valid
583 * session, get going.
584 */
7374c779 585 if (cfg_launchable(cfg)) {
fe8abbf4 586 dlg_end(dlg, 1);
587 } else
588 dlg_beep(dlg);
589 } else if (ctrl == ssd->cancelbutton) {
590 dlg_end(dlg, 0);
591 }
592 }
593}
594
595struct charclass_data {
596 union control *listbox, *editbox, *button;
597};
598
599static void charclass_handler(union control *ctrl, void *dlg,
600 void *data, int event)
601{
602 Config *cfg = (Config *)data;
603 struct charclass_data *ccd =
604 (struct charclass_data *)ctrl->generic.context.p;
605
606 if (event == EVENT_REFRESH) {
607 if (ctrl == ccd->listbox) {
608 int i;
609 dlg_update_start(ctrl, dlg);
610 dlg_listbox_clear(ctrl, dlg);
611 for (i = 0; i < 128; i++) {
612 char str[100];
613 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
614 (i >= 0x21 && i != 0x7F) ? i : ' ', cfg->wordness[i]);
615 dlg_listbox_add(ctrl, dlg, str);
616 }
617 dlg_update_done(ctrl, dlg);
618 }
619 } else if (event == EVENT_ACTION) {
620 if (ctrl == ccd->button) {
621 char str[100];
622 int i, n;
623 dlg_editbox_get(ccd->editbox, dlg, str, sizeof(str));
624 n = atoi(str);
625 for (i = 0; i < 128; i++) {
626 if (dlg_listbox_issel(ccd->listbox, dlg, i))
627 cfg->wordness[i] = n;
628 }
629 dlg_refresh(ccd->listbox, dlg);
630 }
631 }
632}
633
634struct colour_data {
18c2f87c 635 union control *listbox, *redit, *gedit, *bedit, *button;
fe8abbf4 636};
637
638static const char *const colours[] = {
639 "Default Foreground", "Default Bold Foreground",
640 "Default Background", "Default Bold Background",
641 "Cursor Text", "Cursor Colour",
642 "ANSI Black", "ANSI Black Bold",
643 "ANSI Red", "ANSI Red Bold",
644 "ANSI Green", "ANSI Green Bold",
645 "ANSI Yellow", "ANSI Yellow Bold",
646 "ANSI Blue", "ANSI Blue Bold",
647 "ANSI Magenta", "ANSI Magenta Bold",
648 "ANSI Cyan", "ANSI Cyan Bold",
649 "ANSI White", "ANSI White Bold"
650};
651
652static void colour_handler(union control *ctrl, void *dlg,
653 void *data, int event)
654{
655 Config *cfg = (Config *)data;
656 struct colour_data *cd =
657 (struct colour_data *)ctrl->generic.context.p;
daa621ff 658 int update = FALSE, clear = FALSE, r, g, b;
fe8abbf4 659
660 if (event == EVENT_REFRESH) {
661 if (ctrl == cd->listbox) {
662 int i;
663 dlg_update_start(ctrl, dlg);
664 dlg_listbox_clear(ctrl, dlg);
665 for (i = 0; i < lenof(colours); i++)
666 dlg_listbox_add(ctrl, dlg, colours[i]);
667 dlg_update_done(ctrl, dlg);
8b5ee9aa 668 clear = TRUE;
669 update = TRUE;
fe8abbf4 670 }
671 } else if (event == EVENT_SELCHANGE) {
672 if (ctrl == cd->listbox) {
673 /* The user has selected a colour. Update the RGB text. */
674 int i = dlg_listbox_index(ctrl, dlg);
675 if (i < 0) {
8b5ee9aa 676 clear = TRUE;
677 } else {
678 clear = FALSE;
679 r = cfg->colours[i][0];
680 g = cfg->colours[i][1];
681 b = cfg->colours[i][2];
fe8abbf4 682 }
fe8abbf4 683 update = TRUE;
684 }
18c2f87c 685 } else if (event == EVENT_VALCHANGE) {
686 if (ctrl == cd->redit || ctrl == cd->gedit || ctrl == cd->bedit) {
687 /* The user has changed the colour using the edit boxes. */
688 char buf[80];
689 int i, cval;
690
691 dlg_editbox_get(ctrl, dlg, buf, lenof(buf));
3d025d91 692 cval = atoi(buf);
693 if (cval > 255) cval = 255;
694 if (cval < 0) cval = 0;
18c2f87c 695
696 i = dlg_listbox_index(cd->listbox, dlg);
697 if (i >= 0) {
698 if (ctrl == cd->redit)
699 cfg->colours[i][0] = cval;
700 else if (ctrl == cd->gedit)
701 cfg->colours[i][1] = cval;
702 else if (ctrl == cd->bedit)
703 cfg->colours[i][2] = cval;
704 }
705 }
fe8abbf4 706 } else if (event == EVENT_ACTION) {
707 if (ctrl == cd->button) {
708 int i = dlg_listbox_index(cd->listbox, dlg);
709 if (i < 0) {
710 dlg_beep(dlg);
711 return;
712 }
713 /*
714 * Start a colour selector, which will send us an
715 * EVENT_CALLBACK when it's finished and allow us to
716 * pick up the results.
717 */
718 dlg_coloursel_start(ctrl, dlg,
719 cfg->colours[i][0],
720 cfg->colours[i][1],
721 cfg->colours[i][2]);
722 }
723 } else if (event == EVENT_CALLBACK) {
724 if (ctrl == cd->button) {
725 int i = dlg_listbox_index(cd->listbox, dlg);
726 /*
727 * Collect the results of the colour selector. Will
728 * return nonzero on success, or zero if the colour
729 * selector did nothing (user hit Cancel, for example).
730 */
731 if (dlg_coloursel_results(ctrl, dlg, &r, &g, &b)) {
732 cfg->colours[i][0] = r;
733 cfg->colours[i][1] = g;
734 cfg->colours[i][2] = b;
8b5ee9aa 735 clear = FALSE;
fe8abbf4 736 update = TRUE;
737 }
738 }
739 }
740
741 if (update) {
8b5ee9aa 742 if (clear) {
743 dlg_editbox_set(cd->redit, dlg, "");
744 dlg_editbox_set(cd->gedit, dlg, "");
745 dlg_editbox_set(cd->bedit, dlg, "");
746 } else {
747 char buf[40];
748 sprintf(buf, "%d", r); dlg_editbox_set(cd->redit, dlg, buf);
749 sprintf(buf, "%d", g); dlg_editbox_set(cd->gedit, dlg, buf);
750 sprintf(buf, "%d", b); dlg_editbox_set(cd->bedit, dlg, buf);
751 }
fe8abbf4 752 }
753}
754
c6ccd5c2 755struct ttymodes_data {
756 union control *modelist, *valradio, *valbox;
757 union control *addbutton, *rembutton, *listbox;
758};
759
760static void ttymodes_handler(union control *ctrl, void *dlg,
761 void *data, int event)
762{
763 Config *cfg = (Config *)data;
764 struct ttymodes_data *td =
765 (struct ttymodes_data *)ctrl->generic.context.p;
766
767 if (event == EVENT_REFRESH) {
768 if (ctrl == td->listbox) {
769 char *p = cfg->ttymodes;
770 dlg_update_start(ctrl, dlg);
771 dlg_listbox_clear(ctrl, dlg);
772 while (*p) {
773 int tabpos = strchr(p, '\t') - p;
774 char *disp = dupprintf("%.*s\t%s", tabpos, p,
775 (p[tabpos+1] == 'A') ? "(auto)" :
776 p+tabpos+2);
777 dlg_listbox_add(ctrl, dlg, disp);
778 p += strlen(p) + 1;
779 sfree(disp);
780 }
781 dlg_update_done(ctrl, dlg);
782 } else if (ctrl == td->modelist) {
783 int i;
784 dlg_update_start(ctrl, dlg);
785 dlg_listbox_clear(ctrl, dlg);
786 for (i = 0; ttymodes[i]; i++)
787 dlg_listbox_add(ctrl, dlg, ttymodes[i]);
788 dlg_listbox_select(ctrl, dlg, 0); /* *shrug* */
789 dlg_update_done(ctrl, dlg);
790 } else if (ctrl == td->valradio) {
791 dlg_radiobutton_set(ctrl, dlg, 0);
792 }
793 } else if (event == EVENT_ACTION) {
794 if (ctrl == td->addbutton) {
795 int ind = dlg_listbox_index(td->modelist, dlg);
796 if (ind >= 0) {
797 char type = dlg_radiobutton_get(td->valradio, dlg) ? 'V' : 'A';
798 int slen, left;
799 char *p, str[lenof(cfg->ttymodes)];
800 /* Construct new entry */
801 memset(str, 0, lenof(str));
802 strncpy(str, ttymodes[ind], lenof(str)-3);
803 slen = strlen(str);
804 str[slen] = '\t';
805 str[slen+1] = type;
806 slen += 2;
807 if (type == 'V') {
808 dlg_editbox_get(td->valbox, dlg, str+slen, lenof(str)-slen);
809 }
810 /* Find end of list, deleting any existing instance */
811 p = cfg->ttymodes;
812 left = lenof(cfg->ttymodes);
813 while (*p) {
814 int t = strchr(p, '\t') - p;
815 if (t == strlen(ttymodes[ind]) &&
816 strncmp(p, ttymodes[ind], t) == 0) {
817 memmove(p, p+strlen(p)+1, left - (strlen(p)+1));
818 continue;
819 }
820 left -= strlen(p) + 1;
821 p += strlen(p) + 1;
822 }
823 /* Append new entry */
824 memset(p, 0, left);
825 strncpy(p, str, left - 2);
826 dlg_refresh(td->listbox, dlg);
827 } else
828 dlg_beep(dlg);
829 } else if (ctrl == td->rembutton) {
830 char *p = cfg->ttymodes;
831 int i = 0, len = lenof(cfg->ttymodes);
832 while (*p) {
d9268a99 833 int multisel = dlg_listbox_index(td->listbox, dlg) < 0;
c6ccd5c2 834 if (dlg_listbox_issel(td->listbox, dlg, i)) {
d9268a99 835 if (!multisel) {
836 /* Populate controls with entry we're about to
837 * delete, for ease of editing.
838 * (If multiple entries were selected, don't
839 * touch the controls.) */
840 char *val = strchr(p, '\t');
841 if (val) {
842 int ind = 0;
843 val++;
844 while (ttymodes[ind]) {
845 if (strlen(ttymodes[ind]) == val-p-1 &&
846 !strncmp(ttymodes[ind], p, val-p-1))
847 break;
848 ind++;
849 }
850 dlg_listbox_select(td->modelist, dlg, ind);
851 dlg_radiobutton_set(td->valradio, dlg,
852 (*val == 'V'));
853 dlg_editbox_set(td->valbox, dlg, val+1);
854 }
855 }
c6ccd5c2 856 memmove(p, p+strlen(p)+1, len - (strlen(p)+1));
857 i++;
858 continue;
859 }
860 len -= strlen(p) + 1;
861 p += strlen(p) + 1;
862 i++;
863 }
864 memset(p, 0, lenof(cfg->ttymodes) - len);
865 dlg_refresh(td->listbox, dlg);
866 }
867 }
868}
869
fe8abbf4 870struct environ_data {
871 union control *varbox, *valbox, *addbutton, *rembutton, *listbox;
872};
873
874static void environ_handler(union control *ctrl, void *dlg,
875 void *data, int event)
876{
877 Config *cfg = (Config *)data;
878 struct environ_data *ed =
879 (struct environ_data *)ctrl->generic.context.p;
880
881 if (event == EVENT_REFRESH) {
882 if (ctrl == ed->listbox) {
883 char *p = cfg->environmt;
884 dlg_update_start(ctrl, dlg);
885 dlg_listbox_clear(ctrl, dlg);
886 while (*p) {
887 dlg_listbox_add(ctrl, dlg, p);
888 p += strlen(p) + 1;
889 }
890 dlg_update_done(ctrl, dlg);
891 }
892 } else if (event == EVENT_ACTION) {
893 if (ctrl == ed->addbutton) {
894 char str[sizeof(cfg->environmt)];
895 char *p;
896 dlg_editbox_get(ed->varbox, dlg, str, sizeof(str)-1);
897 if (!*str) {
898 dlg_beep(dlg);
899 return;
900 }
901 p = str + strlen(str);
902 *p++ = '\t';
903 dlg_editbox_get(ed->valbox, dlg, p, sizeof(str)-1 - (p - str));
904 if (!*p) {
905 dlg_beep(dlg);
906 return;
907 }
908 p = cfg->environmt;
909 while (*p) {
910 while (*p)
911 p++;
912 p++;
913 }
914 if ((p - cfg->environmt) + strlen(str) + 2 <
915 sizeof(cfg->environmt)) {
916 strcpy(p, str);
917 p[strlen(str) + 1] = '\0';
918 dlg_listbox_add(ed->listbox, dlg, str);
919 dlg_editbox_set(ed->varbox, dlg, "");
920 dlg_editbox_set(ed->valbox, dlg, "");
921 } else {
922 dlg_error_msg(dlg, "Environment too big");
923 }
924 } else if (ctrl == ed->rembutton) {
925 int i = dlg_listbox_index(ed->listbox, dlg);
926 if (i < 0) {
927 dlg_beep(dlg);
928 } else {
d9268a99 929 char *p, *q, *str;
fe8abbf4 930
931 dlg_listbox_del(ed->listbox, dlg, i);
932 p = cfg->environmt;
933 while (i > 0) {
934 if (!*p)
935 goto disaster;
936 while (*p)
937 p++;
938 p++;
939 i--;
940 }
941 q = p;
942 if (!*p)
943 goto disaster;
d9268a99 944 /* Populate controls with the entry we're about to delete
945 * for ease of editing */
946 str = p;
947 p = strchr(p, '\t');
948 if (!p)
949 goto disaster;
950 *p = '\0';
951 dlg_editbox_set(ed->varbox, dlg, str);
952 p++;
953 str = p;
954 dlg_editbox_set(ed->valbox, dlg, str);
955 p = strchr(p, '\0');
956 if (!p)
957 goto disaster;
fe8abbf4 958 p++;
959 while (*p) {
960 while (*p)
961 *q++ = *p++;
962 *q++ = *p++;
963 }
964 *q = '\0';
965 disaster:;
966 }
967 }
968 }
969}
970
971struct portfwd_data {
972 union control *addbutton, *rembutton, *listbox;
973 union control *sourcebox, *destbox, *direction;
89adc0e2 974#ifndef NO_IPV6
05581745 975 union control *addressfamily;
89adc0e2 976#endif
fe8abbf4 977};
978
979static void portfwd_handler(union control *ctrl, void *dlg,
980 void *data, int event)
981{
982 Config *cfg = (Config *)data;
983 struct portfwd_data *pfd =
984 (struct portfwd_data *)ctrl->generic.context.p;
985
986 if (event == EVENT_REFRESH) {
987 if (ctrl == pfd->listbox) {
988 char *p = cfg->portfwd;
989 dlg_update_start(ctrl, dlg);
990 dlg_listbox_clear(ctrl, dlg);
991 while (*p) {
992 dlg_listbox_add(ctrl, dlg, p);
993 p += strlen(p) + 1;
994 }
995 dlg_update_done(ctrl, dlg);
07e4d76d 996 } else if (ctrl == pfd->direction) {
997 /*
998 * Default is Local.
999 */
1000 dlg_radiobutton_set(ctrl, dlg, 0);
89adc0e2 1001#ifndef NO_IPV6
1002 } else if (ctrl == pfd->addressfamily) {
05581745 1003 dlg_radiobutton_set(ctrl, dlg, 0);
89adc0e2 1004#endif
fe8abbf4 1005 }
1006 } else if (event == EVENT_ACTION) {
1007 if (ctrl == pfd->addbutton) {
1008 char str[sizeof(cfg->portfwd)];
1009 char *p;
05581745 1010 int i, type;
1011 int whichbutton;
1012
1013 i = 0;
89adc0e2 1014#ifndef NO_IPV6
05581745 1015 whichbutton = dlg_radiobutton_get(pfd->addressfamily, dlg);
1016 if (whichbutton == 1)
1017 str[i++] = '4';
1018 else if (whichbutton == 2)
1019 str[i++] = '6';
89adc0e2 1020#endif
05581745 1021
1022 whichbutton = dlg_radiobutton_get(pfd->direction, dlg);
820ebe3b 1023 if (whichbutton == 0)
05581745 1024 type = 'L';
820ebe3b 1025 else if (whichbutton == 1)
05581745 1026 type = 'R';
820ebe3b 1027 else
05581745 1028 type = 'D';
1029 str[i++] = type;
1030
1031 dlg_editbox_get(pfd->sourcebox, dlg, str+i, sizeof(str) - i);
94042edc 1032 if (!str[i]) {
fe8abbf4 1033 dlg_error_msg(dlg, "You need to specify a source port number");
1034 return;
1035 }
1036 p = str + strlen(str);
05581745 1037 if (type != 'D') {
820ebe3b 1038 *p++ = '\t';
1039 dlg_editbox_get(pfd->destbox, dlg, p,
e49c58ed 1040 sizeof(str) - (p - str));
820ebe3b 1041 if (!*p || !strchr(p, ':')) {
1042 dlg_error_msg(dlg,
1043 "You need to specify a destination address\n"
1044 "in the form \"host.name:port\"");
1045 return;
1046 }
1047 } else
1048 *p = '\0';
fe8abbf4 1049 p = cfg->portfwd;
1050 while (*p) {
f8ece264 1051 if (strcmp(p,str) == 0) {
1052 dlg_error_msg(dlg, "Specified forwarding already exists");
1053 break;
1054 }
fe8abbf4 1055 while (*p)
1056 p++;
1057 p++;
1058 }
f8ece264 1059 if (!*p) {
1060 if ((p - cfg->portfwd) + strlen(str) + 2 <=
1061 sizeof(cfg->portfwd)) {
1062 strcpy(p, str);
1063 p[strlen(str) + 1] = '\0';
1064 dlg_listbox_add(pfd->listbox, dlg, str);
1065 dlg_editbox_set(pfd->sourcebox, dlg, "");
1066 dlg_editbox_set(pfd->destbox, dlg, "");
1067 } else {
1068 dlg_error_msg(dlg, "Too many forwardings");
1069 }
fe8abbf4 1070 }
1071 } else if (ctrl == pfd->rembutton) {
1072 int i = dlg_listbox_index(pfd->listbox, dlg);
1073 if (i < 0)
1074 dlg_beep(dlg);
1075 else {
d9268a99 1076 char *p, *q, *src, *dst;
1077 char dir;
fe8abbf4 1078
1079 dlg_listbox_del(pfd->listbox, dlg, i);
1080 p = cfg->portfwd;
1081 while (i > 0) {
1082 if (!*p)
1083 goto disaster2;
1084 while (*p)
1085 p++;
1086 p++;
1087 i--;
1088 }
1089 q = p;
1090 if (!*p)
1091 goto disaster2;
d9268a99 1092 /* Populate the controls with the entry we're about to
1093 * delete, for ease of editing. */
1094 {
1095 static const char *const afs = "A46";
1096 char *afp = strchr(afs, *p);
a97cd780 1097#ifndef NO_IPV6
d9268a99 1098 int idx = afp ? afp-afs : 0;
a97cd780 1099#endif
d9268a99 1100 if (afp)
1101 p++;
1102#ifndef NO_IPV6
1103 dlg_radiobutton_set(pfd->addressfamily, dlg, idx);
1104#endif
1105 }
1106 {
1107 static const char *const dirs = "LRD";
1108 dir = *p;
1109 dlg_radiobutton_set(pfd->direction, dlg,
1110 strchr(dirs, dir) - dirs);
1111 }
1112 p++;
1113 if (dir != 'D') {
1114 src = p;
1115 p = strchr(p, '\t');
1116 if (!p)
1117 goto disaster2;
1118 *p = '\0';
fe8abbf4 1119 p++;
d9268a99 1120 dst = p;
1121 } else {
1122 src = p;
1123 dst = "";
1124 }
1125 p = strchr(p, '\0');
1126 if (!p)
1127 goto disaster2;
1128 dlg_editbox_set(pfd->sourcebox, dlg, src);
1129 dlg_editbox_set(pfd->destbox, dlg, dst);
fe8abbf4 1130 p++;
1131 while (*p) {
1132 while (*p)
1133 *q++ = *p++;
1134 *q++ = *p++;
1135 }
1136 *q = '\0';
1137 disaster2:;
1138 }
1139 }
1140 }
1141}
1142
12745e35 1143void setup_config_box(struct controlbox *b, int midsession,
1144 int protocol, int protcfginfo)
fe8abbf4 1145{
1146 struct controlset *s;
1147 struct sessionsaver_data *ssd;
1148 struct charclass_data *ccd;
1149 struct colour_data *cd;
c6ccd5c2 1150 struct ttymodes_data *td;
fe8abbf4 1151 struct environ_data *ed;
1152 struct portfwd_data *pfd;
1153 union control *c;
f6f450e2 1154 char *str;
fe8abbf4 1155
1156 ssd = (struct sessionsaver_data *)
1157 ctrl_alloc(b, sizeof(struct sessionsaver_data));
56b9b9a7 1158 memset(ssd, 0, sizeof(*ssd));
2e155f47 1159 ssd->midsession = midsession;
fe8abbf4 1160
1161 /*
1162 * The standard panel that appears at the bottom of all panels:
1163 * Open, Cancel, Apply etc.
1164 */
1165 s = ctrl_getset(b, "", "", "");
1166 ctrl_columns(s, 5, 20, 20, 20, 20, 20);
1167 ssd->okbutton = ctrl_pushbutton(s,
1168 (midsession ? "Apply" : "Open"),
1169 (char)(midsession ? 'a' : 'o'),
1170 HELPCTX(no_help),
1171 sessionsaver_handler, P(ssd));
1172 ssd->okbutton->button.isdefault = TRUE;
1173 ssd->okbutton->generic.column = 3;
1174 ssd->cancelbutton = ctrl_pushbutton(s, "Cancel", 'c', HELPCTX(no_help),
1175 sessionsaver_handler, P(ssd));
0bd8d76d 1176 ssd->cancelbutton->button.iscancel = TRUE;
fe8abbf4 1177 ssd->cancelbutton->generic.column = 4;
1178 /* We carefully don't close the 5-column part, so that platform-
1179 * specific add-ons can put extra buttons alongside Open and Cancel. */
1180
1181 /*
1182 * The Session panel.
1183 */
f6f450e2 1184 str = dupprintf("Basic options for your %s session", appname);
1185 ctrl_settitle(b, "Session", str);
1186 sfree(str);
fe8abbf4 1187
1188 if (!midsession) {
7374c779 1189 struct hostport *hp = (struct hostport *)
1190 ctrl_alloc(b, sizeof(struct hostport));
7374c779 1191
fe8abbf4 1192 s = ctrl_getset(b, "Session", "hostport",
7374c779 1193 "Specify the destination you want to connect to");
fe8abbf4 1194 ctrl_columns(s, 2, 75, 25);
7374c779 1195 c = ctrl_editbox(s, HOST_BOX_TITLE, 'n', 100,
fe8abbf4 1196 HELPCTX(session_hostname),
7374c779 1197 config_host_handler, I(0), I(0));
fe8abbf4 1198 c->generic.column = 0;
7374c779 1199 hp->host = c;
1200 c = ctrl_editbox(s, PORT_BOX_TITLE, 'p', 100,
1201 HELPCTX(session_hostname),
1202 config_port_handler, I(0), I(0));
fe8abbf4 1203 c->generic.column = 1;
7374c779 1204 hp->port = c;
fe8abbf4 1205 ctrl_columns(s, 1, 100);
7374c779 1206
9e164d82 1207 if (!backend_from_proto(PROT_SSH)) {
7374c779 1208 ctrl_radiobuttons(s, "Connection type:", NO_SHORTCUT, 3,
fe8abbf4 1209 HELPCTX(session_hostname),
7374c779 1210 config_protocolbuttons_handler, P(hp),
063f6c96 1211 "Raw", 'w', I(PROT_RAW),
fe8abbf4 1212 "Telnet", 't', I(PROT_TELNET),
1213 "Rlogin", 'i', I(PROT_RLOGIN),
1214 NULL);
1215 } else {
7374c779 1216 ctrl_radiobuttons(s, "Connection type:", NO_SHORTCUT, 4,
fe8abbf4 1217 HELPCTX(session_hostname),
7374c779 1218 config_protocolbuttons_handler, P(hp),
063f6c96 1219 "Raw", 'w', I(PROT_RAW),
fe8abbf4 1220 "Telnet", 't', I(PROT_TELNET),
1221 "Rlogin", 'i', I(PROT_RLOGIN),
1222 "SSH", 's', I(PROT_SSH),
1223 NULL);
1224 }
fe8abbf4 1225 }
1226
48c4dd7c 1227 /*
1228 * The Load/Save panel is available even in mid-session.
1229 */
1230 s = ctrl_getset(b, "Session", "savedsessions",
59b8cd5a 1231 midsession ? "Save the current session settings" :
48c4dd7c 1232 "Load, save or delete a stored session");
1233 ctrl_columns(s, 2, 75, 25);
12745e35 1234 get_sesslist(&ssd->sesslist, TRUE);
48c4dd7c 1235 ssd->editbox = ctrl_editbox(s, "Saved Sessions", 'e', 100,
1236 HELPCTX(session_saved),
1237 sessionsaver_handler, P(ssd), P(NULL));
1238 ssd->editbox->generic.column = 0;
1239 /* Reset columns so that the buttons are alongside the list, rather
1240 * than alongside that edit box. */
1241 ctrl_columns(s, 1, 100);
1242 ctrl_columns(s, 2, 75, 25);
1243 ssd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1244 HELPCTX(session_saved),
1245 sessionsaver_handler, P(ssd));
1246 ssd->listbox->generic.column = 0;
1247 ssd->listbox->listbox.height = 7;
2e155f47 1248 if (!midsession) {
1249 ssd->loadbutton = ctrl_pushbutton(s, "Load", 'l',
1250 HELPCTX(session_saved),
1251 sessionsaver_handler, P(ssd));
1252 ssd->loadbutton->generic.column = 1;
1253 } else {
1254 /* We can't offer the Load button mid-session, as it would allow the
1255 * user to load and subsequently save settings they can't see. (And
1256 * also change otherwise immutable settings underfoot; that probably
1257 * shouldn't be a problem, but.) */
1258 ssd->loadbutton = NULL;
1259 }
1260 /* "Save" button is permitted mid-session. */
48c4dd7c 1261 ssd->savebutton = ctrl_pushbutton(s, "Save", 'v',
1262 HELPCTX(session_saved),
1263 sessionsaver_handler, P(ssd));
1264 ssd->savebutton->generic.column = 1;
2e155f47 1265 if (!midsession) {
1266 ssd->delbutton = ctrl_pushbutton(s, "Delete", 'd',
1267 HELPCTX(session_saved),
1268 sessionsaver_handler, P(ssd));
1269 ssd->delbutton->generic.column = 1;
1270 } else {
1271 /* Disable the Delete button mid-session too, for UI consistency. */
1272 ssd->delbutton = NULL;
1273 }
48c4dd7c 1274 ctrl_columns(s, 1, 100);
1275
fe8abbf4 1276 s = ctrl_getset(b, "Session", "otheropts", NULL);
063f6c96 1277 c = ctrl_radiobuttons(s, "Close window on exit:", 'x', 4,
fe8abbf4 1278 HELPCTX(session_coe),
1279 dlg_stdradiobutton_handler,
1280 I(offsetof(Config, close_on_exit)),
1281 "Always", I(FORCE_ON),
1282 "Never", I(FORCE_OFF),
1283 "Only on clean exit", I(AUTO), NULL);
1284
1285 /*
1286 * The Session/Logging panel.
1287 */
1288 ctrl_settitle(b, "Session/Logging", "Options controlling session logging");
1289
1290 s = ctrl_getset(b, "Session/Logging", "main", NULL);
3e547dd8 1291 /*
1292 * The logging buttons change depending on whether SSH packet
1293 * logging can sensibly be available.
1294 */
1295 {
bf8a49a1 1296 char *sshlogname, *sshrawlogname;
3e547dd8 1297 if ((midsession && protocol == PROT_SSH) ||
9e164d82 1298 (!midsession && backend_from_proto(PROT_SSH))) {
bf8a49a1 1299 sshlogname = "SSH packets";
1300 sshrawlogname = "SSH packets and raw data";
1301 } else {
1302 sshlogname = NULL; /* this will disable both buttons */
1303 sshrawlogname = NULL; /* this will just placate optimisers */
1304 }
1305 ctrl_radiobuttons(s, "Session logging:", NO_SHORTCUT, 2,
3e547dd8 1306 HELPCTX(logging_main),
17556692 1307 loggingbuttons_handler,
3e547dd8 1308 I(offsetof(Config, logtype)),
bf8a49a1 1309 "None", 't', I(LGTYP_NONE),
1310 "Printable output", 'p', I(LGTYP_ASCII),
1311 "All session output", 'l', I(LGTYP_DEBUG),
3e547dd8 1312 sshlogname, 's', I(LGTYP_PACKETS),
bf8a49a1 1313 sshrawlogname, 'r', I(LGTYP_SSHRAW),
3e547dd8 1314 NULL);
1315 }
fe8abbf4 1316 ctrl_filesel(s, "Log file name:", 'f',
1317 NULL, TRUE, "Select session log file name",
1318 HELPCTX(logging_filename),
1319 dlg_stdfilesel_handler, I(offsetof(Config, logfilename)));
1320 ctrl_text(s, "(Log file name can contain &Y, &M, &D for date,"
1321 " &T for time, and &H for host name)",
1322 HELPCTX(logging_filename));
1323 ctrl_radiobuttons(s, "What to do if the log file already exists:", 'e', 1,
1324 HELPCTX(logging_exists),
1325 dlg_stdradiobutton_handler, I(offsetof(Config,logxfovr)),
1326 "Always overwrite it", I(LGXF_OVR),
1327 "Always append to the end of it", I(LGXF_APN),
1328 "Ask the user every time", I(LGXF_ASK), NULL);
6d60c791 1329 ctrl_checkbox(s, "Flush log file frequently", 'u',
1330 HELPCTX(logging_flush),
1331 dlg_stdcheckbox_handler, I(offsetof(Config,logflush)));
fe8abbf4 1332
9a10ecf4 1333 if ((midsession && protocol == PROT_SSH) ||
9e164d82 1334 (!midsession && backend_from_proto(PROT_SSH))) {
9a10ecf4 1335 s = ctrl_getset(b, "Session/Logging", "ssh",
1336 "Options specific to SSH packet logging");
1337 ctrl_checkbox(s, "Omit known password fields", 'k',
1338 HELPCTX(logging_ssh_omit_password),
1339 dlg_stdcheckbox_handler, I(offsetof(Config,logomitpass)));
1340 ctrl_checkbox(s, "Omit session data", 'd',
1341 HELPCTX(logging_ssh_omit_data),
1342 dlg_stdcheckbox_handler, I(offsetof(Config,logomitdata)));
1343 }
1344
fe8abbf4 1345 /*
1346 * The Terminal panel.
1347 */
1348 ctrl_settitle(b, "Terminal", "Options controlling the terminal emulation");
1349
1350 s = ctrl_getset(b, "Terminal", "general", "Set various terminal options");
1351 ctrl_checkbox(s, "Auto wrap mode initially on", 'w',
1352 HELPCTX(terminal_autowrap),
1353 dlg_stdcheckbox_handler, I(offsetof(Config,wrap_mode)));
1354 ctrl_checkbox(s, "DEC Origin Mode initially on", 'd',
1355 HELPCTX(terminal_decom),
1356 dlg_stdcheckbox_handler, I(offsetof(Config,dec_om)));
1357 ctrl_checkbox(s, "Implicit CR in every LF", 'r',
1358 HELPCTX(terminal_lfhascr),
1359 dlg_stdcheckbox_handler, I(offsetof(Config,lfhascr)));
7612f22f 1360 ctrl_checkbox(s, "Implicit LF in every CR", 'f',
1361 HELPCTX(terminal_crhaslf),
1362 dlg_stdcheckbox_handler, I(offsetof(Config,crhaslf)));
fe8abbf4 1363 ctrl_checkbox(s, "Use background colour to erase screen", 'e',
1364 HELPCTX(terminal_bce),
1365 dlg_stdcheckbox_handler, I(offsetof(Config,bce)));
1366 ctrl_checkbox(s, "Enable blinking text", 'n',
1367 HELPCTX(terminal_blink),
1368 dlg_stdcheckbox_handler, I(offsetof(Config,blinktext)));
1369 ctrl_editbox(s, "Answerback to ^E:", 's', 100,
1370 HELPCTX(terminal_answerback),
1371 dlg_stdeditbox_handler, I(offsetof(Config,answerback)),
1372 I(sizeof(((Config *)0)->answerback)));
1373
1374 s = ctrl_getset(b, "Terminal", "ldisc", "Line discipline options");
1375 ctrl_radiobuttons(s, "Local echo:", 'l', 3,
1376 HELPCTX(terminal_localecho),
1377 dlg_stdradiobutton_handler,I(offsetof(Config,localecho)),
1378 "Auto", I(AUTO),
1379 "Force on", I(FORCE_ON),
1380 "Force off", I(FORCE_OFF), NULL);
1381 ctrl_radiobuttons(s, "Local line editing:", 't', 3,
1382 HELPCTX(terminal_localedit),
1383 dlg_stdradiobutton_handler,I(offsetof(Config,localedit)),
1384 "Auto", I(AUTO),
1385 "Force on", I(FORCE_ON),
1386 "Force off", I(FORCE_OFF), NULL);
1387
1388 s = ctrl_getset(b, "Terminal", "printing", "Remote-controlled printing");
1389 ctrl_combobox(s, "Printer to send ANSI printer output to:", 'p', 100,
1390 HELPCTX(terminal_printing),
1391 printerbox_handler, P(NULL), P(NULL));
1392
1393 /*
1394 * The Terminal/Keyboard panel.
1395 */
1396 ctrl_settitle(b, "Terminal/Keyboard",
1397 "Options controlling the effects of keys");
1398
1399 s = ctrl_getset(b, "Terminal/Keyboard", "mappings",
1400 "Change the sequences sent by:");
1401 ctrl_radiobuttons(s, "The Backspace key", 'b', 2,
1402 HELPCTX(keyboard_backspace),
1403 dlg_stdradiobutton_handler,
1404 I(offsetof(Config, bksp_is_delete)),
1405 "Control-H", I(0), "Control-? (127)", I(1), NULL);
1406 ctrl_radiobuttons(s, "The Home and End keys", 'e', 2,
1407 HELPCTX(keyboard_homeend),
1408 dlg_stdradiobutton_handler,
1409 I(offsetof(Config, rxvt_homeend)),
1410 "Standard", I(0), "rxvt", I(1), NULL);
1411 ctrl_radiobuttons(s, "The Function keys and keypad", 'f', 3,
1412 HELPCTX(keyboard_funkeys),
1413 dlg_stdradiobutton_handler,
1414 I(offsetof(Config, funky_type)),
1415 "ESC[n~", I(0), "Linux", I(1), "Xterm R6", I(2),
1416 "VT400", I(3), "VT100+", I(4), "SCO", I(5), NULL);
1417
1418 s = ctrl_getset(b, "Terminal/Keyboard", "appkeypad",
1419 "Application keypad settings:");
1420 ctrl_radiobuttons(s, "Initial state of cursor keys:", 'r', 3,
1421 HELPCTX(keyboard_appcursor),
1422 dlg_stdradiobutton_handler,
1423 I(offsetof(Config, app_cursor)),
1424 "Normal", I(0), "Application", I(1), NULL);
1425 ctrl_radiobuttons(s, "Initial state of numeric keypad:", 'n', 3,
1426 HELPCTX(keyboard_appkeypad),
1427 numeric_keypad_handler, P(NULL),
1428 "Normal", I(0), "Application", I(1), "NetHack", I(2),
1429 NULL);
1430
1431 /*
1432 * The Terminal/Bell panel.
1433 */
1434 ctrl_settitle(b, "Terminal/Bell",
1435 "Options controlling the terminal bell");
1436
1437 s = ctrl_getset(b, "Terminal/Bell", "style", "Set the style of bell");
1438 ctrl_radiobuttons(s, "Action to happen when a bell occurs:", 'b', 1,
1439 HELPCTX(bell_style),
1440 dlg_stdradiobutton_handler, I(offsetof(Config, beep)),
1441 "None (bell disabled)", I(BELL_DISABLED),
1442 "Make default system alert sound", I(BELL_DEFAULT),
1443 "Visual bell (flash window)", I(BELL_VISUAL), NULL);
1444
1445 s = ctrl_getset(b, "Terminal/Bell", "overload",
1446 "Control the bell overload behaviour");
1447 ctrl_checkbox(s, "Bell is temporarily disabled when over-used", 'd',
1448 HELPCTX(bell_overload),
1449 dlg_stdcheckbox_handler, I(offsetof(Config,bellovl)));
1450 ctrl_editbox(s, "Over-use means this many bells...", 'm', 20,
1451 HELPCTX(bell_overload),
1452 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_n)), I(-1));
1453 ctrl_editbox(s, "... in this many seconds", 't', 20,
1454 HELPCTX(bell_overload),
1455 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_t)),
62697e04 1456 I(-TICKSPERSEC));
fe8abbf4 1457 ctrl_text(s, "The bell is re-enabled after a few seconds of silence.",
1458 HELPCTX(bell_overload));
1459 ctrl_editbox(s, "Seconds of silence required", 's', 20,
1460 HELPCTX(bell_overload),
1461 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_s)),
62697e04 1462 I(-TICKSPERSEC));
fe8abbf4 1463
1464 /*
1465 * The Terminal/Features panel.
1466 */
1467 ctrl_settitle(b, "Terminal/Features",
1468 "Enabling and disabling advanced terminal features");
1469
1470 s = ctrl_getset(b, "Terminal/Features", "main", NULL);
1471 ctrl_checkbox(s, "Disable application cursor keys mode", 'u',
1472 HELPCTX(features_application),
1473 dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_c)));
1474 ctrl_checkbox(s, "Disable application keypad mode", 'k',
1475 HELPCTX(features_application),
1476 dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_k)));
1477 ctrl_checkbox(s, "Disable xterm-style mouse reporting", 'x',
1478 HELPCTX(features_mouse),
1479 dlg_stdcheckbox_handler, I(offsetof(Config,no_mouse_rep)));
1480 ctrl_checkbox(s, "Disable remote-controlled terminal resizing", 's',
1481 HELPCTX(features_resize),
1482 dlg_stdcheckbox_handler,
1483 I(offsetof(Config,no_remote_resize)));
1484 ctrl_checkbox(s, "Disable switching to alternate terminal screen", 'w',
1485 HELPCTX(features_altscreen),
1486 dlg_stdcheckbox_handler, I(offsetof(Config,no_alt_screen)));
1487 ctrl_checkbox(s, "Disable remote-controlled window title changing", 't',
1488 HELPCTX(features_retitle),
1489 dlg_stdcheckbox_handler,
1490 I(offsetof(Config,no_remote_wintitle)));
e65096f2 1491 ctrl_radiobuttons(s, "Response to remote title query (SECURITY):", 'q', 3,
1492 HELPCTX(features_qtitle),
1493 dlg_stdradiobutton_handler,
1494 I(offsetof(Config,remote_qtitle_action)),
1495 "None", I(TITLE_NONE),
1496 "Empty string", I(TITLE_EMPTY),
1497 "Window title", I(TITLE_REAL), NULL);
fe8abbf4 1498 ctrl_checkbox(s, "Disable destructive backspace on server sending ^?",'b',
1499 HELPCTX(features_dbackspace),
1500 dlg_stdcheckbox_handler, I(offsetof(Config,no_dbackspace)));
1501 ctrl_checkbox(s, "Disable remote-controlled character set configuration",
1502 'r', HELPCTX(features_charset), dlg_stdcheckbox_handler,
1503 I(offsetof(Config,no_remote_charset)));
f0fccd51 1504 ctrl_checkbox(s, "Disable Arabic text shaping",
f4ec0818 1505 'l', HELPCTX(features_arabicshaping), dlg_stdcheckbox_handler,
f0fccd51 1506 I(offsetof(Config, arabicshaping)));
1507 ctrl_checkbox(s, "Disable bidirectional text display",
f4ec0818 1508 'd', HELPCTX(features_bidi), dlg_stdcheckbox_handler,
f0fccd51 1509 I(offsetof(Config, bidi)));
fe8abbf4 1510
1511 /*
1512 * The Window panel.
1513 */
f6f450e2 1514 str = dupprintf("Options controlling %s's window", appname);
1515 ctrl_settitle(b, "Window", str);
1516 sfree(str);
fe8abbf4 1517
1518 s = ctrl_getset(b, "Window", "size", "Set the size of the window");
1519 ctrl_columns(s, 2, 50, 50);
fe8abbf4 1520 c = ctrl_editbox(s, "Columns", 'm', 100,
1521 HELPCTX(window_size),
1522 dlg_stdeditbox_handler, I(offsetof(Config,width)), I(-1));
b8e45023 1523 c->generic.column = 0;
1524 c = ctrl_editbox(s, "Rows", 'r', 100,
1525 HELPCTX(window_size),
1526 dlg_stdeditbox_handler, I(offsetof(Config,height)),I(-1));
fe8abbf4 1527 c->generic.column = 1;
1528 ctrl_columns(s, 1, 100);
1529
1530 s = ctrl_getset(b, "Window", "scrollback",
1531 "Control the scrollback in the window");
1532 ctrl_editbox(s, "Lines of scrollback", 's', 50,
1533 HELPCTX(window_scrollback),
1534 dlg_stdeditbox_handler, I(offsetof(Config,savelines)), I(-1));
1535 ctrl_checkbox(s, "Display scrollbar", 'd',
1536 HELPCTX(window_scrollback),
1537 dlg_stdcheckbox_handler, I(offsetof(Config,scrollbar)));
fe8abbf4 1538 ctrl_checkbox(s, "Reset scrollback on keypress", 'k',
1539 HELPCTX(window_scrollback),
1540 dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_key)));
1541 ctrl_checkbox(s, "Reset scrollback on display activity", 'p',
1542 HELPCTX(window_scrollback),
1543 dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_disp)));
876e5d5e 1544 ctrl_checkbox(s, "Push erased text into scrollback", 'e',
1545 HELPCTX(window_erased),
1546 dlg_stdcheckbox_handler,
1547 I(offsetof(Config,erase_to_scrollback)));
fe8abbf4 1548
1549 /*
1550 * The Window/Appearance panel.
1551 */
f6f450e2 1552 str = dupprintf("Configure the appearance of %s's window", appname);
1553 ctrl_settitle(b, "Window/Appearance", str);
1554 sfree(str);
fe8abbf4 1555
1556 s = ctrl_getset(b, "Window/Appearance", "cursor",
1557 "Adjust the use of the cursor");
1558 ctrl_radiobuttons(s, "Cursor appearance:", NO_SHORTCUT, 3,
1559 HELPCTX(appearance_cursor),
1560 dlg_stdradiobutton_handler,
1561 I(offsetof(Config, cursor_type)),
1562 "Block", 'l', I(0),
1563 "Underline", 'u', I(1),
1564 "Vertical line", 'v', I(2), NULL);
1565 ctrl_checkbox(s, "Cursor blinks", 'b',
1566 HELPCTX(appearance_cursor),
1567 dlg_stdcheckbox_handler, I(offsetof(Config,blink_cur)));
1568
1569 s = ctrl_getset(b, "Window/Appearance", "font",
1570 "Font settings");
1571 ctrl_fontsel(s, "Font used in the terminal window", 'n',
1572 HELPCTX(appearance_font),
1573 dlg_stdfontsel_handler, I(offsetof(Config, font)));
1574
1575 s = ctrl_getset(b, "Window/Appearance", "mouse",
1576 "Adjust the use of the mouse pointer");
1577 ctrl_checkbox(s, "Hide mouse pointer when typing in window", 'p',
1578 HELPCTX(appearance_hidemouse),
1579 dlg_stdcheckbox_handler, I(offsetof(Config,hide_mouseptr)));
1580
1581 s = ctrl_getset(b, "Window/Appearance", "border",
1582 "Adjust the window border");
b908db15 1583 ctrl_editbox(s, "Gap between text and window edge:", 'e', 20,
fe8abbf4 1584 HELPCTX(appearance_border),
1585 dlg_stdeditbox_handler,
1586 I(offsetof(Config,window_border)), I(-1));
1587
1588 /*
1589 * The Window/Behaviour panel.
1590 */
f6f450e2 1591 str = dupprintf("Configure the behaviour of %s's window", appname);
1592 ctrl_settitle(b, "Window/Behaviour", str);
1593 sfree(str);
fe8abbf4 1594
1595 s = ctrl_getset(b, "Window/Behaviour", "title",
1596 "Adjust the behaviour of the window title");
1597 ctrl_editbox(s, "Window title:", 't', 100,
1598 HELPCTX(appearance_title),
1599 dlg_stdeditbox_handler, I(offsetof(Config,wintitle)),
1600 I(sizeof(((Config *)0)->wintitle)));
1601 ctrl_checkbox(s, "Separate window and icon titles", 'i',
1602 HELPCTX(appearance_title),
1603 dlg_stdcheckbox_handler,
1604 I(CHECKBOX_INVERT | offsetof(Config,win_name_always)));
1605
1606 s = ctrl_getset(b, "Window/Behaviour", "main", NULL);
1607 ctrl_checkbox(s, "Warn before closing window", 'w',
1608 HELPCTX(behaviour_closewarn),
1609 dlg_stdcheckbox_handler, I(offsetof(Config,warn_on_close)));
1610
1611 /*
1612 * The Window/Translation panel.
1613 */
1614 ctrl_settitle(b, "Window/Translation",
1615 "Options controlling character set translation");
1616
1617 s = ctrl_getset(b, "Window/Translation", "trans",
b44d65f4 1618 "Character set translation");
1619 ctrl_combobox(s, "Remote character set:",
fe8abbf4 1620 'r', 100, HELPCTX(translation_codepage),
1621 codepage_handler, P(NULL), P(NULL));
1622
74790953 1623 s = ctrl_getset(b, "Window/Translation", "tweaks", NULL);
1624 ctrl_checkbox(s, "Treat CJK ambiguous characters as wide", 'w',
1625 HELPCTX(translation_cjk_ambig_wide),
1626 dlg_stdcheckbox_handler, I(offsetof(Config,cjk_ambig_wide)));
1627
00381fc7 1628 str = dupprintf("Adjust how %s handles line drawing characters", appname);
f6f450e2 1629 s = ctrl_getset(b, "Window/Translation", "linedraw", str);
1630 sfree(str);
fe8abbf4 1631 ctrl_radiobuttons(s, "Handling of line drawing characters:", NO_SHORTCUT,1,
1632 HELPCTX(translation_linedraw),
1633 dlg_stdradiobutton_handler,
1634 I(offsetof(Config, vtmode)),
3900c2d6 1635 "Use Unicode line drawing code points",'u',I(VT_UNICODE),
fe8abbf4 1636 "Poor man's line drawing (+, - and |)",'p',I(VT_POORMAN),
3900c2d6 1637 NULL);
00381fc7 1638 ctrl_checkbox(s, "Copy and paste line drawing characters as lqqqk",'d',
1639 HELPCTX(selection_linedraw),
1640 dlg_stdcheckbox_handler, I(offsetof(Config,rawcnp)));
fe8abbf4 1641
1642 /*
1643 * The Window/Selection panel.
1644 */
1645 ctrl_settitle(b, "Window/Selection", "Options controlling copy and paste");
fe8abbf4 1646
1647 s = ctrl_getset(b, "Window/Selection", "mouse",
1648 "Control use of mouse");
1649 ctrl_checkbox(s, "Shift overrides application's use of mouse", 'p',
1650 HELPCTX(selection_shiftdrag),
1651 dlg_stdcheckbox_handler, I(offsetof(Config,mouse_override)));
1652 ctrl_radiobuttons(s,
1653 "Default selection mode (Alt+drag does the other one):",
1654 NO_SHORTCUT, 2,
1655 HELPCTX(selection_rect),
1656 dlg_stdradiobutton_handler,
1657 I(offsetof(Config, rect_select)),
1658 "Normal", 'n', I(0),
1659 "Rectangular block", 'r', I(1), NULL);
1660
1661 s = ctrl_getset(b, "Window/Selection", "charclass",
1662 "Control the select-one-word-at-a-time mode");
1663 ccd = (struct charclass_data *)
1664 ctrl_alloc(b, sizeof(struct charclass_data));
1665 ccd->listbox = ctrl_listbox(s, "Character classes:", 'e',
1666 HELPCTX(selection_charclasses),
1667 charclass_handler, P(ccd));
1668 ccd->listbox->listbox.multisel = 1;
1669 ccd->listbox->listbox.ncols = 4;
3d88e64d 1670 ccd->listbox->listbox.percentages = snewn(4, int);
fe8abbf4 1671 ccd->listbox->listbox.percentages[0] = 15;
1672 ccd->listbox->listbox.percentages[1] = 25;
1673 ccd->listbox->listbox.percentages[2] = 20;
1674 ccd->listbox->listbox.percentages[3] = 40;
1675 ctrl_columns(s, 2, 67, 33);
1676 ccd->editbox = ctrl_editbox(s, "Set to class", 't', 50,
1677 HELPCTX(selection_charclasses),
1678 charclass_handler, P(ccd), P(NULL));
1679 ccd->editbox->generic.column = 0;
1680 ccd->button = ctrl_pushbutton(s, "Set", 's',
1681 HELPCTX(selection_charclasses),
1682 charclass_handler, P(ccd));
1683 ccd->button->generic.column = 1;
1684 ctrl_columns(s, 1, 100);
1685
1686 /*
1687 * The Window/Colours panel.
1688 */
1689 ctrl_settitle(b, "Window/Colours", "Options controlling use of colours");
1690
1691 s = ctrl_getset(b, "Window/Colours", "general",
1692 "General options for colour usage");
c6f1b8ed 1693 ctrl_checkbox(s, "Allow terminal to specify ANSI colours", 'i',
1694 HELPCTX(colours_ansi),
1695 dlg_stdcheckbox_handler, I(offsetof(Config,ansi_colour)));
cecb13f6 1696 ctrl_checkbox(s, "Allow terminal to use xterm 256-colour mode", '2',
1697 HELPCTX(colours_xterm256), dlg_stdcheckbox_handler,
1698 I(offsetof(Config,xterm_256_colour)));
fe8abbf4 1699 ctrl_checkbox(s, "Bolded text is a different colour", 'b',
1700 HELPCTX(colours_bold),
1701 dlg_stdcheckbox_handler, I(offsetof(Config,bold_colour)));
1702
f6f450e2 1703 str = dupprintf("Adjust the precise colours %s displays", appname);
1704 s = ctrl_getset(b, "Window/Colours", "adjust", str);
1705 sfree(str);
fe8abbf4 1706 ctrl_text(s, "Select a colour from the list, and then click the"
1707 " Modify button to change its appearance.",
1708 HELPCTX(colours_config));
1709 ctrl_columns(s, 2, 67, 33);
1710 cd = (struct colour_data *)ctrl_alloc(b, sizeof(struct colour_data));
1711 cd->listbox = ctrl_listbox(s, "Select a colour to adjust:", 'u',
1712 HELPCTX(colours_config), colour_handler, P(cd));
1713 cd->listbox->generic.column = 0;
18c2f87c 1714 cd->listbox->listbox.height = 7;
fe8abbf4 1715 c = ctrl_text(s, "RGB value:", HELPCTX(colours_config));
1716 c->generic.column = 1;
18c2f87c 1717 cd->redit = ctrl_editbox(s, "Red", 'r', 50, HELPCTX(colours_config),
1718 colour_handler, P(cd), P(NULL));
1719 cd->redit->generic.column = 1;
1720 cd->gedit = ctrl_editbox(s, "Green", 'n', 50, HELPCTX(colours_config),
1721 colour_handler, P(cd), P(NULL));
1722 cd->gedit->generic.column = 1;
1723 cd->bedit = ctrl_editbox(s, "Blue", 'e', 50, HELPCTX(colours_config),
1724 colour_handler, P(cd), P(NULL));
1725 cd->bedit->generic.column = 1;
fe8abbf4 1726 cd->button = ctrl_pushbutton(s, "Modify", 'm', HELPCTX(colours_config),
1727 colour_handler, P(cd));
1728 cd->button->generic.column = 1;
1729 ctrl_columns(s, 1, 100);
1730
1731 /*
3e547dd8 1732 * The Connection panel. This doesn't show up if we're in a
1733 * non-network utility such as pterm. We tell this by being
1734 * passed a protocol < 0.
fe8abbf4 1735 */
3e547dd8 1736 if (protocol >= 0) {
1737 ctrl_settitle(b, "Connection", "Options controlling the connection");
1738
05581745 1739 s = ctrl_getset(b, "Connection", "keepalive",
1740 "Sending of null packets to keep session active");
1741 ctrl_editbox(s, "Seconds between keepalives (0 to turn off)", 'k', 20,
1742 HELPCTX(connection_keepalive),
1743 dlg_stdeditbox_handler, I(offsetof(Config,ping_interval)),
1744 I(-1));
1745
3e547dd8 1746 if (!midsession) {
05581745 1747 s = ctrl_getset(b, "Connection", "tcp",
1748 "Low-level TCP connection options");
1749 ctrl_checkbox(s, "Disable Nagle's algorithm (TCP_NODELAY option)",
1750 'n', HELPCTX(connection_nodelay),
1751 dlg_stdcheckbox_handler,
1752 I(offsetof(Config,tcp_nodelay)));
1753 ctrl_checkbox(s, "Enable TCP keepalives (SO_KEEPALIVE option)",
1754 'p', HELPCTX(connection_tcpkeepalive),
1755 dlg_stdcheckbox_handler,
1756 I(offsetof(Config,tcp_keepalives)));
22db244f 1757#ifndef NO_IPV6
05581745 1758 s = ctrl_getset(b, "Connection", "ipversion",
1759 "Internet protocol version");
22db244f 1760 ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
05581745 1761 HELPCTX(connection_ipversion),
1762 dlg_stdradiobutton_handler,
1763 I(offsetof(Config, addressfamily)),
b908db15 1764 "Auto", 'u', I(ADDRTYPE_UNSPEC),
1765 "IPv4", '4', I(ADDRTYPE_IPV4),
1766 "IPv6", '6', I(ADDRTYPE_IPV6),
05581745 1767 NULL);
22db244f 1768#endif
881da168 1769
2875af11 1770 {
1771 char *label = backend_from_proto(PROT_SSH) ?
1772 "Logical name of remote host (e.g. for SSH key lookup):" :
1773 "Logical name of remote host:";
1774 s = ctrl_getset(b, "Connection", "identity",
1775 "Logical name of remote host");
1776 ctrl_editbox(s, label, 'm', 100,
1777 HELPCTX(connection_loghost),
1778 dlg_stdeditbox_handler, I(offsetof(Config,loghost)),
1779 I(sizeof(((Config *)0)->loghost)));
1780 }
05581745 1781 }
1782
1783 /*
1784 * A sub-panel Connection/Data, containing options that
1785 * decide on data to send to the server.
1786 */
1787 if (!midsession) {
1788 ctrl_settitle(b, "Connection/Data", "Data to send to the server");
1789
1790 s = ctrl_getset(b, "Connection/Data", "login",
1791 "Login details");
1792 ctrl_editbox(s, "Auto-login username", 'u', 50,
1793 HELPCTX(connection_username),
1794 dlg_stdeditbox_handler, I(offsetof(Config,username)),
1795 I(sizeof(((Config *)0)->username)));
471c20b0 1796 {
1797 /* We assume the local username is sufficiently stable
1798 * to include on the dialog box. */
1799 char *user = get_username();
4c26bb50 1800 char *userlabel = dupprintf("Use system username (%s)",
1801 user ? user : "");
471c20b0 1802 sfree(user);
1803 ctrl_radiobuttons(s, "When username is not specified:", 'n', 4,
1804 HELPCTX(connection_username_from_env),
1805 dlg_stdradiobutton_handler,
1806 I(offsetof(Config, username_from_env)),
1807 "Prompt", I(FALSE),
1808 userlabel, I(TRUE),
1809 NULL);
1810 sfree(userlabel);
1811 }
05581745 1812
1813 s = ctrl_getset(b, "Connection/Data", "term",
1814 "Terminal details");
3e547dd8 1815 ctrl_editbox(s, "Terminal-type string", 't', 50,
1816 HELPCTX(connection_termtype),
1817 dlg_stdeditbox_handler, I(offsetof(Config,termtype)),
1818 I(sizeof(((Config *)0)->termtype)));
a5dd8467 1819 ctrl_editbox(s, "Terminal speeds", 's', 50,
1820 HELPCTX(connection_termspeed),
1821 dlg_stdeditbox_handler, I(offsetof(Config,termspeed)),
1822 I(sizeof(((Config *)0)->termspeed)));
73feed4f 1823
05581745 1824 s = ctrl_getset(b, "Connection/Data", "env",
1825 "Environment variables");
73feed4f 1826 ctrl_columns(s, 2, 80, 20);
1827 ed = (struct environ_data *)
1828 ctrl_alloc(b, sizeof(struct environ_data));
1829 ed->varbox = ctrl_editbox(s, "Variable", 'v', 60,
1830 HELPCTX(telnet_environ),
1831 environ_handler, P(ed), P(NULL));
1832 ed->varbox->generic.column = 0;
1833 ed->valbox = ctrl_editbox(s, "Value", 'l', 60,
1834 HELPCTX(telnet_environ),
1835 environ_handler, P(ed), P(NULL));
1836 ed->valbox->generic.column = 0;
1837 ed->addbutton = ctrl_pushbutton(s, "Add", 'd',
1838 HELPCTX(telnet_environ),
1839 environ_handler, P(ed));
1840 ed->addbutton->generic.column = 1;
1841 ed->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1842 HELPCTX(telnet_environ),
1843 environ_handler, P(ed));
1844 ed->rembutton->generic.column = 1;
1845 ctrl_columns(s, 1, 100);
1846 ed->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1847 HELPCTX(telnet_environ),
1848 environ_handler, P(ed));
1849 ed->listbox->listbox.height = 3;
1850 ed->listbox->listbox.ncols = 2;
1851 ed->listbox->listbox.percentages = snewn(2, int);
1852 ed->listbox->listbox.percentages[0] = 30;
1853 ed->listbox->listbox.percentages[1] = 70;
3e547dd8 1854 }
fe8abbf4 1855
fe8abbf4 1856 }
1857
1858 if (!midsession) {
1859 /*
1860 * The Connection/Proxy panel.
1861 */
1862 ctrl_settitle(b, "Connection/Proxy",
1863 "Options controlling proxy usage");
1864
10068a0b 1865 s = ctrl_getset(b, "Connection/Proxy", "basics", NULL);
1866 ctrl_radiobuttons(s, "Proxy type:", 't', 3,
fe8abbf4 1867 HELPCTX(proxy_type),
1868 dlg_stdradiobutton_handler,
1869 I(offsetof(Config, proxy_type)),
0f0a2507 1870 "None", I(PROXY_NONE),
10068a0b 1871 "SOCKS 4", I(PROXY_SOCKS4),
1872 "SOCKS 5", I(PROXY_SOCKS5),
0f0a2507 1873 "HTTP", I(PROXY_HTTP),
0f0a2507 1874 "Telnet", I(PROXY_TELNET),
fe8abbf4 1875 NULL);
1876 ctrl_columns(s, 2, 80, 20);
1877 c = ctrl_editbox(s, "Proxy hostname", 'y', 100,
1878 HELPCTX(proxy_main),
1879 dlg_stdeditbox_handler,
1880 I(offsetof(Config,proxy_host)),
1881 I(sizeof(((Config *)0)->proxy_host)));
1882 c->generic.column = 0;
1883 c = ctrl_editbox(s, "Port", 'p', 100,
1884 HELPCTX(proxy_main),
1885 dlg_stdeditbox_handler,
1886 I(offsetof(Config,proxy_port)),
1887 I(-1));
1888 c->generic.column = 1;
1889 ctrl_columns(s, 1, 100);
1890 ctrl_editbox(s, "Exclude Hosts/IPs", 'e', 100,
1891 HELPCTX(proxy_exclude),
1892 dlg_stdeditbox_handler,
1893 I(offsetof(Config,proxy_exclude_list)),
1894 I(sizeof(((Config *)0)->proxy_exclude_list)));
1895 ctrl_checkbox(s, "Consider proxying local host connections", 'x',
1896 HELPCTX(proxy_exclude),
1897 dlg_stdcheckbox_handler,
1898 I(offsetof(Config,even_proxy_localhost)));
1899 ctrl_radiobuttons(s, "Do DNS name lookup at proxy end:", 'd', 3,
1900 HELPCTX(proxy_dns),
1901 dlg_stdradiobutton_handler,
1902 I(offsetof(Config, proxy_dns)),
1903 "No", I(FORCE_OFF),
1904 "Auto", I(AUTO),
1905 "Yes", I(FORCE_ON), NULL);
1906 ctrl_editbox(s, "Username", 'u', 60,
1907 HELPCTX(proxy_auth),
1908 dlg_stdeditbox_handler,
1909 I(offsetof(Config,proxy_username)),
1910 I(sizeof(((Config *)0)->proxy_username)));
1911 c = ctrl_editbox(s, "Password", 'w', 60,
1912 HELPCTX(proxy_auth),
1913 dlg_stdeditbox_handler,
1914 I(offsetof(Config,proxy_password)),
1915 I(sizeof(((Config *)0)->proxy_password)));
1916 c->editbox.password = 1;
fe8abbf4 1917 ctrl_editbox(s, "Telnet command", 'm', 100,
1918 HELPCTX(proxy_command),
1919 dlg_stdeditbox_handler,
1920 I(offsetof(Config,proxy_telnet_command)),
1921 I(sizeof(((Config *)0)->proxy_telnet_command)));
fe8abbf4 1922 }
1923
1924 /*
1925 * The Telnet panel exists in the base config box, and in a
1926 * mid-session reconfig box _if_ we're using Telnet.
1927 */
1928 if (!midsession || protocol == PROT_TELNET) {
1929 /*
1930 * The Connection/Telnet panel.
1931 */
1932 ctrl_settitle(b, "Connection/Telnet",
1933 "Options controlling Telnet connections");
1934
fe8abbf4 1935 s = ctrl_getset(b, "Connection/Telnet", "protocol",
1936 "Telnet protocol adjustments");
1937
1938 if (!midsession) {
1939 ctrl_radiobuttons(s, "Handling of OLD_ENVIRON ambiguity:",
1940 NO_SHORTCUT, 2,
1941 HELPCTX(telnet_oldenviron),
1942 dlg_stdradiobutton_handler,
1943 I(offsetof(Config, rfc_environ)),
1944 "BSD (commonplace)", 'b', I(0),
1945 "RFC 1408 (unusual)", 'f', I(1), NULL);
1946 ctrl_radiobuttons(s, "Telnet negotiation mode:", 't', 2,
1947 HELPCTX(telnet_passive),
1948 dlg_stdradiobutton_handler,
1949 I(offsetof(Config, passive_telnet)),
1950 "Passive", I(1), "Active", I(0), NULL);
1951 }
76d3d354 1952 ctrl_checkbox(s, "Keyboard sends Telnet special commands", 'k',
fe8abbf4 1953 HELPCTX(telnet_specialkeys),
1954 dlg_stdcheckbox_handler,
1955 I(offsetof(Config,telnet_keyboard)));
76d3d354 1956 ctrl_checkbox(s, "Return key sends Telnet New Line instead of ^M",
1957 'm', HELPCTX(telnet_newline),
fe8abbf4 1958 dlg_stdcheckbox_handler,
1959 I(offsetof(Config,telnet_newline)));
1960 }
1961
1962 if (!midsession) {
1963
1964 /*
1965 * The Connection/Rlogin panel.
1966 */
1967 ctrl_settitle(b, "Connection/Rlogin",
1968 "Options controlling Rlogin connections");
1969
1970 s = ctrl_getset(b, "Connection/Rlogin", "data",
1971 "Data to send to the server");
fe8abbf4 1972 ctrl_editbox(s, "Local username:", 'l', 50,
1973 HELPCTX(rlogin_localuser),
1974 dlg_stdeditbox_handler, I(offsetof(Config,localusername)),
1975 I(sizeof(((Config *)0)->localusername)));
1976
1977 }
1978
1979 /*
fda2feb1 1980 * All the SSH stuff is omitted in PuTTYtel, or in a reconfig
1981 * when we're not doing SSH.
fe8abbf4 1982 */
1983
9e164d82 1984 if (backend_from_proto(PROT_SSH) && (!midsession || protocol == PROT_SSH)) {
fe8abbf4 1985
1986 /*
1987 * The Connection/SSH panel.
1988 */
1989 ctrl_settitle(b, "Connection/SSH",
1990 "Options controlling SSH connections");
1991
e13bba36 1992 if (midsession && protcfginfo == 1) {
fda2feb1 1993 s = ctrl_getset(b, "Connection/SSH", "disclaimer", NULL);
1994 ctrl_text(s, "Nothing on this panel may be reconfigured in mid-"
1995 "session; it is only here so that sub-panels of it can "
1996 "exist without looking strange.", HELPCTX(no_help));
1997 }
1998
1999 if (!midsession) {
2000
2001 s = ctrl_getset(b, "Connection/SSH", "data",
2002 "Data to send to the server");
2003 ctrl_editbox(s, "Remote command:", 'r', 100,
2004 HELPCTX(ssh_command),
2005 dlg_stdeditbox_handler, I(offsetof(Config,remote_cmd)),
2006 I(sizeof(((Config *)0)->remote_cmd)));
2007
2008 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
fda2feb1 2009 ctrl_checkbox(s, "Don't start a shell or command at all", 'n',
2010 HELPCTX(ssh_noshell),
2011 dlg_stdcheckbox_handler,
2012 I(offsetof(Config,ssh_no_shell)));
e13bba36 2013 }
2014
2015 if (!midsession || protcfginfo != 1) {
2016 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
2017
fda2feb1 2018 ctrl_checkbox(s, "Enable compression", 'e',
2019 HELPCTX(ssh_compress),
2020 dlg_stdcheckbox_handler,
2021 I(offsetof(Config,compression)));
e13bba36 2022 }
2023
2024 if (!midsession) {
2025 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
2026
fda2feb1 2027 ctrl_radiobuttons(s, "Preferred SSH protocol version:", NO_SHORTCUT, 4,
2028 HELPCTX(ssh_protocol),
2029 dlg_stdradiobutton_handler,
2030 I(offsetof(Config, sshprot)),
2031 "1 only", 'l', I(0),
2032 "1", '1', I(1),
2033 "2", '2', I(2),
2034 "2 only", 'y', I(3), NULL);
e13bba36 2035 }
fda2feb1 2036
e13bba36 2037 if (!midsession || protcfginfo != 1) {
fda2feb1 2038 s = ctrl_getset(b, "Connection/SSH", "encryption", "Encryption options");
2039 c = ctrl_draglist(s, "Encryption cipher selection policy:", 's',
2040 HELPCTX(ssh_ciphers),
2041 cipherlist_handler, P(NULL));
2042 c->listbox.height = 6;
2043
2e85c969 2044 ctrl_checkbox(s, "Enable legacy use of single-DES in SSH-2", 'i',
bb524800 2045 HELPCTX(ssh_ciphers),
fda2feb1 2046 dlg_stdcheckbox_handler,
2047 I(offsetof(Config,ssh2_des_cbc)));
e6c1536e 2048 }
fe8abbf4 2049
e6c1536e 2050 /*
2051 * The Connection/SSH/Kex panel. (Owing to repeat key
f89c3294 2052 * exchange, this is all meaningful in mid-session _if_
2e85c969 2053 * we're using SSH-2 or haven't decided yet.)
e6c1536e 2054 */
f89c3294 2055 if (protcfginfo != 1) {
2056 ctrl_settitle(b, "Connection/SSH/Kex",
2057 "Options controlling SSH key exchange");
2058
2059 s = ctrl_getset(b, "Connection/SSH/Kex", "main",
2060 "Key exchange algorithm options");
2e077f2e 2061 c = ctrl_draglist(s, "Algorithm selection policy:", 's',
f89c3294 2062 HELPCTX(ssh_kexlist),
2063 kexlist_handler, P(NULL));
2064 c->listbox.height = 5;
2065
2066 s = ctrl_getset(b, "Connection/SSH/Kex", "repeat",
2067 "Options controlling key re-exchange");
2068
2069 ctrl_editbox(s, "Max minutes before rekey (0 for no limit)", 't', 20,
2070 HELPCTX(ssh_kex_repeat),
2071 dlg_stdeditbox_handler,
2072 I(offsetof(Config,ssh_rekey_time)),
2073 I(-1));
2074 ctrl_editbox(s, "Max data before rekey (0 for no limit)", 'x', 20,
2075 HELPCTX(ssh_kex_repeat),
2076 dlg_stdeditbox_handler,
2077 I(offsetof(Config,ssh_rekey_data)),
2078 I(16));
2079 ctrl_text(s, "(Use 1M for 1 megabyte, 1G for 1 gigabyte etc)",
2080 HELPCTX(ssh_kex_repeat));
2081 }
e6c1536e 2082
2083 if (!midsession) {
83e7d008 2084
fda2feb1 2085 /*
2086 * The Connection/SSH/Auth panel.
2087 */
2088 ctrl_settitle(b, "Connection/SSH/Auth",
2089 "Options controlling SSH authentication");
fe8abbf4 2090
a1a1fae4 2091 s = ctrl_getset(b, "Connection/SSH/Auth", "main", NULL);
2092 ctrl_checkbox(s, "Bypass authentication entirely (SSH-2 only)", 'b',
2093 HELPCTX(ssh_auth_bypass),
2094 dlg_stdcheckbox_handler,
2095 I(offsetof(Config,ssh_no_userauth)));
adb6167a 2096 ctrl_checkbox(s, "Display pre-authentication banner (SSH-2 only)",
2097 'd', HELPCTX(ssh_auth_banner),
2098 dlg_stdcheckbox_handler,
2099 I(offsetof(Config,ssh_show_banner)));
a1a1fae4 2100
fda2feb1 2101 s = ctrl_getset(b, "Connection/SSH/Auth", "methods",
2102 "Authentication methods");
973612f5 2103 ctrl_checkbox(s, "Attempt authentication using Pageant", 'p',
2104 HELPCTX(ssh_auth_pageant),
2105 dlg_stdcheckbox_handler,
2106 I(offsetof(Config,tryagent)));
2e85c969 2107 ctrl_checkbox(s, "Attempt TIS or CryptoCard auth (SSH-1)", 'm',
fda2feb1 2108 HELPCTX(ssh_auth_tis),
2109 dlg_stdcheckbox_handler,
2110 I(offsetof(Config,try_tis_auth)));
2e85c969 2111 ctrl_checkbox(s, "Attempt \"keyboard-interactive\" auth (SSH-2)",
fda2feb1 2112 'i', HELPCTX(ssh_auth_ki),
2113 dlg_stdcheckbox_handler,
2114 I(offsetof(Config,try_ki_auth)));
2115
2116 s = ctrl_getset(b, "Connection/SSH/Auth", "params",
2117 "Authentication parameters");
2118 ctrl_checkbox(s, "Allow agent forwarding", 'f',
2119 HELPCTX(ssh_auth_agentfwd),
2120 dlg_stdcheckbox_handler, I(offsetof(Config,agentfwd)));
b3d375b2 2121 ctrl_checkbox(s, "Allow attempted changes of username in SSH-2", NO_SHORTCUT,
fda2feb1 2122 HELPCTX(ssh_auth_changeuser),
2123 dlg_stdcheckbox_handler,
2124 I(offsetof(Config,change_username)));
2125 ctrl_filesel(s, "Private key file for authentication:", 'k',
2126 FILTER_KEY_FILES, FALSE, "Select private key file",
2127 HELPCTX(ssh_auth_privkey),
2128 dlg_stdfilesel_handler, I(offsetof(Config, keyfile)));
b3d375b2 2129
2130#ifndef NO_GSSAPI
2131 /*
1e00c92b 2132 * Connection/SSH/Auth/GSSAPI, which sadly won't fit on
2133 * the main Auth panel.
2134 */
2135 ctrl_settitle(b, "Connection/SSH/Auth/GSSAPI",
2136 "Options controlling GSSAPI authentication");
2137 s = ctrl_getset(b, "Connection/SSH/Auth/GSSAPI", "gssapi", NULL);
2138
2139 ctrl_checkbox(s, "Attempt GSSAPI authentication (SSH-2 only)",
d53faed4 2140 't', HELPCTX(ssh_gssapi),
1e00c92b 2141 dlg_stdcheckbox_handler,
2142 I(offsetof(Config,try_gssapi_auth)));
2143
ad404f42 2144 ctrl_checkbox(s, "Allow GSSAPI credential delegation", 'l',
1e00c92b 2145 HELPCTX(ssh_gssapi_delegation),
2146 dlg_stdcheckbox_handler,
2147 I(offsetof(Config,gssapifwd)));
2148
2149 /*
b3d375b2 2150 * GSSAPI library selection.
2151 */
2152 if (ngsslibs > 1) {
d53faed4 2153 c = ctrl_draglist(s, "Preference order for GSSAPI libraries:",
ad404f42 2154 'p', HELPCTX(ssh_gssapi_libraries),
b3d375b2 2155 gsslist_handler, P(NULL));
2156 c->listbox.height = ngsslibs;
1e00c92b 2157
2158 /*
2159 * I currently assume that if more than one GSS
2160 * library option is available, then one of them is
2161 * 'user-supplied' and so we should present the
2162 * following file selector. This is at least half-
2163 * reasonable, because if we're using statically
2164 * linked GSSAPI then there will only be one option
2165 * and no way to load from a user-supplied library,
2166 * whereas if we're using dynamic libraries then
2167 * there will almost certainly be some default
2168 * option in addition to a user-supplied path. If
2169 * anyone ever ports PuTTY to a system on which
2170 * dynamic-library GSSAPI is available but there is
2171 * absolutely no consensus on where to keep the
2172 * libraries, there'll need to be a flag alongside
2173 * ngsslibs to control whether the file selector is
2174 * displayed.
2175 */
2176
ad404f42 2177 ctrl_filesel(s, "User-supplied GSSAPI library path:", 's',
1e00c92b 2178 FILTER_DYNLIB_FILES, FALSE, "Select library file",
2179 HELPCTX(ssh_gssapi_libraries),
2180 dlg_stdfilesel_handler,
2181 I(offsetof(Config, ssh_gss_custom)));
b3d375b2 2182 }
2183#endif
fda2feb1 2184 }
fe8abbf4 2185
fda2feb1 2186 if (!midsession) {
05581745 2187 /*
c6ccd5c2 2188 * The Connection/SSH/TTY panel.
2189 */
2190 ctrl_settitle(b, "Connection/SSH/TTY", "Remote terminal settings");
2191
2192 s = ctrl_getset(b, "Connection/SSH/TTY", "sshtty", NULL);
2193 ctrl_checkbox(s, "Don't allocate a pseudo-terminal", 'p',
2194 HELPCTX(ssh_nopty),
2195 dlg_stdcheckbox_handler,
2196 I(offsetof(Config,nopty)));
2197
2198 s = ctrl_getset(b, "Connection/SSH/TTY", "ttymodes",
2199 "Terminal modes");
2200 td = (struct ttymodes_data *)
2201 ctrl_alloc(b, sizeof(struct ttymodes_data));
2202 ctrl_columns(s, 2, 75, 25);
2203 c = ctrl_text(s, "Terminal modes to send:", HELPCTX(ssh_ttymodes));
2204 c->generic.column = 0;
2205 td->rembutton = ctrl_pushbutton(s, "Remove", 'r',
2206 HELPCTX(ssh_ttymodes),
2207 ttymodes_handler, P(td));
2208 td->rembutton->generic.column = 1;
2209 td->rembutton->generic.tabdelay = 1;
2210 ctrl_columns(s, 1, 100);
2211 td->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
2212 HELPCTX(ssh_ttymodes),
2213 ttymodes_handler, P(td));
2214 td->listbox->listbox.multisel = 1;
2215 td->listbox->listbox.height = 4;
2216 td->listbox->listbox.ncols = 2;
2217 td->listbox->listbox.percentages = snewn(2, int);
2218 td->listbox->listbox.percentages[0] = 40;
2219 td->listbox->listbox.percentages[1] = 60;
2220 ctrl_tabdelay(s, td->rembutton);
2221 ctrl_columns(s, 2, 75, 25);
2222 td->modelist = ctrl_droplist(s, "Mode:", 'm', 67,
2223 HELPCTX(ssh_ttymodes),
2224 ttymodes_handler, P(td));
2225 td->modelist->generic.column = 0;
2226 td->addbutton = ctrl_pushbutton(s, "Add", 'd',
2227 HELPCTX(ssh_ttymodes),
2228 ttymodes_handler, P(td));
2229 td->addbutton->generic.column = 1;
2230 td->addbutton->generic.tabdelay = 1;
2231 ctrl_columns(s, 1, 100); /* column break */
2232 /* Bit of a hack to get the value radio buttons and
2233 * edit-box on the same row. */
2234 ctrl_columns(s, 3, 25, 50, 25);
2235 c = ctrl_text(s, "Value:", HELPCTX(ssh_ttymodes));
2236 c->generic.column = 0;
2237 td->valradio = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 2,
2238 HELPCTX(ssh_ttymodes),
2239 ttymodes_handler, P(td),
2240 "Auto", NO_SHORTCUT, P(NULL),
2241 "This:", NO_SHORTCUT, P(NULL),
2242 NULL);
2243 td->valradio->generic.column = 1;
2244 td->valbox = ctrl_editbox(s, NULL, NO_SHORTCUT, 100,
2245 HELPCTX(ssh_ttymodes),
2246 ttymodes_handler, P(td), P(NULL));
2247 td->valbox->generic.column = 2;
2248 ctrl_tabdelay(s, td->addbutton);
2249
2250 }
2251
2252 if (!midsession) {
2253 /*
05581745 2254 * The Connection/SSH/X11 panel.
2255 */
2256 ctrl_settitle(b, "Connection/SSH/X11",
2257 "Options controlling SSH X11 forwarding");
2258
2259 s = ctrl_getset(b, "Connection/SSH/X11", "x11", "X11 forwarding");
fda2feb1 2260 ctrl_checkbox(s, "Enable X11 forwarding", 'e',
2261 HELPCTX(ssh_tunnels_x11),
2262 dlg_stdcheckbox_handler,I(offsetof(Config,x11_forward)));
2263 ctrl_editbox(s, "X display location", 'x', 50,
2264 HELPCTX(ssh_tunnels_x11),
2265 dlg_stdeditbox_handler, I(offsetof(Config,x11_display)),
2266 I(sizeof(((Config *)0)->x11_display)));
2267 ctrl_radiobuttons(s, "Remote X11 authentication protocol", 'u', 2,
2268 HELPCTX(ssh_tunnels_x11auth),
2269 dlg_stdradiobutton_handler,
2270 I(offsetof(Config, x11_auth)),
2271 "MIT-Magic-Cookie-1", I(X11_MIT),
2272 "XDM-Authorization-1", I(X11_XDM), NULL);
2273 }
fe8abbf4 2274
05581745 2275 /*
2276 * The Tunnels panel _is_ still available in mid-session.
2277 */
2278 ctrl_settitle(b, "Connection/SSH/Tunnels",
2279 "Options controlling SSH port forwarding");
2280
fe8abbf4 2281 s = ctrl_getset(b, "Connection/SSH/Tunnels", "portfwd",
2282 "Port forwarding");
2283 ctrl_checkbox(s, "Local ports accept connections from other hosts",'t',
2284 HELPCTX(ssh_tunnels_portfwd_localhost),
2285 dlg_stdcheckbox_handler,
2286 I(offsetof(Config,lport_acceptall)));
2e85c969 2287 ctrl_checkbox(s, "Remote ports do the same (SSH-2 only)", 'p',
fe8abbf4 2288 HELPCTX(ssh_tunnels_portfwd_localhost),
2289 dlg_stdcheckbox_handler,
2290 I(offsetof(Config,rport_acceptall)));
2291
2292 ctrl_columns(s, 3, 55, 20, 25);
2293 c = ctrl_text(s, "Forwarded ports:", HELPCTX(ssh_tunnels_portfwd));
2294 c->generic.column = COLUMN_FIELD(0,2);
2295 /* You want to select from the list, _then_ hit Remove. So tab order
2296 * should be that way round. */
2297 pfd = (struct portfwd_data *)ctrl_alloc(b,sizeof(struct portfwd_data));
2298 pfd->rembutton = ctrl_pushbutton(s, "Remove", 'r',
2299 HELPCTX(ssh_tunnels_portfwd),
2300 portfwd_handler, P(pfd));
2301 pfd->rembutton->generic.column = 2;
2302 pfd->rembutton->generic.tabdelay = 1;
2303 pfd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
2304 HELPCTX(ssh_tunnels_portfwd),
2305 portfwd_handler, P(pfd));
2306 pfd->listbox->listbox.height = 3;
37dbf11c 2307 pfd->listbox->listbox.ncols = 2;
3d88e64d 2308 pfd->listbox->listbox.percentages = snewn(2, int);
37dbf11c 2309 pfd->listbox->listbox.percentages[0] = 20;
2310 pfd->listbox->listbox.percentages[1] = 80;
fe8abbf4 2311 ctrl_tabdelay(s, pfd->rembutton);
2312 ctrl_text(s, "Add new forwarded port:", HELPCTX(ssh_tunnels_portfwd));
2313 /* You want to enter source, destination and type, _then_ hit Add.
2314 * Again, we adjust the tab order to reflect this. */
2315 pfd->addbutton = ctrl_pushbutton(s, "Add", 'd',
2316 HELPCTX(ssh_tunnels_portfwd),
2317 portfwd_handler, P(pfd));
2318 pfd->addbutton->generic.column = 2;
2319 pfd->addbutton->generic.tabdelay = 1;
2320 pfd->sourcebox = ctrl_editbox(s, "Source port", 's', 40,
2321 HELPCTX(ssh_tunnels_portfwd),
2322 portfwd_handler, P(pfd), P(NULL));
2323 pfd->sourcebox->generic.column = 0;
2324 pfd->destbox = ctrl_editbox(s, "Destination", 'i', 67,
2325 HELPCTX(ssh_tunnels_portfwd),
2326 portfwd_handler, P(pfd), P(NULL));
820ebe3b 2327 pfd->direction = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
fe8abbf4 2328 HELPCTX(ssh_tunnels_portfwd),
2329 portfwd_handler, P(pfd),
2330 "Local", 'l', P(NULL),
820ebe3b 2331 "Remote", 'm', P(NULL),
2332 "Dynamic", 'y', P(NULL),
2333 NULL);
05581745 2334#ifndef NO_IPV6
22db244f 2335 pfd->addressfamily =
2336 ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
05581745 2337 HELPCTX(ssh_tunnels_portfwd_ipversion),
2338 portfwd_handler, P(pfd),
b908db15 2339 "Auto", 'u', I(ADDRTYPE_UNSPEC),
2340 "IPv4", '4', I(ADDRTYPE_IPV4),
2341 "IPv6", '6', I(ADDRTYPE_IPV6),
05581745 2342 NULL);
22db244f 2343#endif
fe8abbf4 2344 ctrl_tabdelay(s, pfd->addbutton);
2345 ctrl_columns(s, 1, 100);
2346
fda2feb1 2347 if (!midsession) {
2348 /*
2349 * The Connection/SSH/Bugs panel.
2350 */
2351 ctrl_settitle(b, "Connection/SSH/Bugs",
2352 "Workarounds for SSH server bugs");
2353
2354 s = ctrl_getset(b, "Connection/SSH/Bugs", "main",
2355 "Detection of known bugs in SSH servers");
2e85c969 2356 ctrl_droplist(s, "Chokes on SSH-1 ignore messages", 'i', 20,
fda2feb1 2357 HELPCTX(ssh_bugs_ignore1),
2358 sshbug_handler, I(offsetof(Config,sshbug_ignore1)));
2e85c969 2359 ctrl_droplist(s, "Refuses all SSH-1 password camouflage", 's', 20,
fda2feb1 2360 HELPCTX(ssh_bugs_plainpw1),
2361 sshbug_handler, I(offsetof(Config,sshbug_plainpw1)));
2e85c969 2362 ctrl_droplist(s, "Chokes on SSH-1 RSA authentication", 'r', 20,
fda2feb1 2363 HELPCTX(ssh_bugs_rsa1),
2364 sshbug_handler, I(offsetof(Config,sshbug_rsa1)));
cf6ddb95 2365 ctrl_droplist(s, "Chokes on SSH-2 ignore messages", '2', 20,
2366 HELPCTX(ssh_bugs_ignore2),
2367 sshbug_handler, I(offsetof(Config,sshbug_ignore2)));
2e85c969 2368 ctrl_droplist(s, "Miscomputes SSH-2 HMAC keys", 'm', 20,
fda2feb1 2369 HELPCTX(ssh_bugs_hmac2),
2370 sshbug_handler, I(offsetof(Config,sshbug_hmac2)));
2e85c969 2371 ctrl_droplist(s, "Miscomputes SSH-2 encryption keys", 'e', 20,
fda2feb1 2372 HELPCTX(ssh_bugs_derivekey2),
2373 sshbug_handler, I(offsetof(Config,sshbug_derivekey2)));
2e85c969 2374 ctrl_droplist(s, "Requires padding on SSH-2 RSA signatures", 'p', 20,
fda2feb1 2375 HELPCTX(ssh_bugs_rsapad2),
2376 sshbug_handler, I(offsetof(Config,sshbug_rsapad2)));
19f47a7d 2377 ctrl_droplist(s, "Misuses the session ID in SSH-2 PK auth", 'n', 20,
fda2feb1 2378 HELPCTX(ssh_bugs_pksessid2),
2379 sshbug_handler, I(offsetof(Config,sshbug_pksessid2)));
19f47a7d 2380 ctrl_droplist(s, "Handles SSH-2 key re-exchange badly", 'k', 20,
f382c87d 2381 HELPCTX(ssh_bugs_rekey2),
2382 sshbug_handler, I(offsetof(Config,sshbug_rekey2)));
c9739dba 2383 ctrl_droplist(s, "Ignores SSH-2 maximum packet size", 'x', 20,
2384 HELPCTX(ssh_bugs_maxpkt2),
2385 sshbug_handler, I(offsetof(Config,sshbug_maxpkt2)));
fda2feb1 2386 }
fe8abbf4 2387 }
2388}