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