Work around a bug in early versions of GTK (which I'm still forced
[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;
626 int update = FALSE, r, g, b;
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);
18c2f87c 636 dlg_editbox_set(cd->redit, dlg, "");
637 dlg_editbox_set(cd->gedit, dlg, "");
638 dlg_editbox_set(cd->bedit, dlg, "");
fe8abbf4 639 }
640 } else if (event == EVENT_SELCHANGE) {
641 if (ctrl == cd->listbox) {
642 /* The user has selected a colour. Update the RGB text. */
643 int i = dlg_listbox_index(ctrl, dlg);
644 if (i < 0) {
645 dlg_beep(dlg);
646 return;
647 }
648 r = cfg->colours[i][0];
649 g = cfg->colours[i][1];
650 b = cfg->colours[i][2];
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;
703 update = TRUE;
704 }
705 }
706 }
707
708 if (update) {
709 char buf[40];
18c2f87c 710 sprintf(buf, "%d", r); dlg_editbox_set(cd->redit, dlg, buf);
711 sprintf(buf, "%d", g); dlg_editbox_set(cd->gedit, dlg, buf);
712 sprintf(buf, "%d", b); dlg_editbox_set(cd->bedit, dlg, buf);
fe8abbf4 713 }
714}
715
c6ccd5c2 716struct ttymodes_data {
717 union control *modelist, *valradio, *valbox;
718 union control *addbutton, *rembutton, *listbox;
719};
720
721static void ttymodes_handler(union control *ctrl, void *dlg,
722 void *data, int event)
723{
724 Config *cfg = (Config *)data;
725 struct ttymodes_data *td =
726 (struct ttymodes_data *)ctrl->generic.context.p;
727
728 if (event == EVENT_REFRESH) {
729 if (ctrl == td->listbox) {
730 char *p = cfg->ttymodes;
731 dlg_update_start(ctrl, dlg);
732 dlg_listbox_clear(ctrl, dlg);
733 while (*p) {
734 int tabpos = strchr(p, '\t') - p;
735 char *disp = dupprintf("%.*s\t%s", tabpos, p,
736 (p[tabpos+1] == 'A') ? "(auto)" :
737 p+tabpos+2);
738 dlg_listbox_add(ctrl, dlg, disp);
739 p += strlen(p) + 1;
740 sfree(disp);
741 }
742 dlg_update_done(ctrl, dlg);
743 } else if (ctrl == td->modelist) {
744 int i;
745 dlg_update_start(ctrl, dlg);
746 dlg_listbox_clear(ctrl, dlg);
747 for (i = 0; ttymodes[i]; i++)
748 dlg_listbox_add(ctrl, dlg, ttymodes[i]);
749 dlg_listbox_select(ctrl, dlg, 0); /* *shrug* */
750 dlg_update_done(ctrl, dlg);
751 } else if (ctrl == td->valradio) {
752 dlg_radiobutton_set(ctrl, dlg, 0);
753 }
754 } else if (event == EVENT_ACTION) {
755 if (ctrl == td->addbutton) {
756 int ind = dlg_listbox_index(td->modelist, dlg);
757 if (ind >= 0) {
758 char type = dlg_radiobutton_get(td->valradio, dlg) ? 'V' : 'A';
759 int slen, left;
760 char *p, str[lenof(cfg->ttymodes)];
761 /* Construct new entry */
762 memset(str, 0, lenof(str));
763 strncpy(str, ttymodes[ind], lenof(str)-3);
764 slen = strlen(str);
765 str[slen] = '\t';
766 str[slen+1] = type;
767 slen += 2;
768 if (type == 'V') {
769 dlg_editbox_get(td->valbox, dlg, str+slen, lenof(str)-slen);
770 }
771 /* Find end of list, deleting any existing instance */
772 p = cfg->ttymodes;
773 left = lenof(cfg->ttymodes);
774 while (*p) {
775 int t = strchr(p, '\t') - p;
776 if (t == strlen(ttymodes[ind]) &&
777 strncmp(p, ttymodes[ind], t) == 0) {
778 memmove(p, p+strlen(p)+1, left - (strlen(p)+1));
779 continue;
780 }
781 left -= strlen(p) + 1;
782 p += strlen(p) + 1;
783 }
784 /* Append new entry */
785 memset(p, 0, left);
786 strncpy(p, str, left - 2);
787 dlg_refresh(td->listbox, dlg);
788 } else
789 dlg_beep(dlg);
790 } else if (ctrl == td->rembutton) {
791 char *p = cfg->ttymodes;
792 int i = 0, len = lenof(cfg->ttymodes);
793 while (*p) {
d9268a99 794 int multisel = dlg_listbox_index(td->listbox, dlg) < 0;
c6ccd5c2 795 if (dlg_listbox_issel(td->listbox, dlg, i)) {
d9268a99 796 if (!multisel) {
797 /* Populate controls with entry we're about to
798 * delete, for ease of editing.
799 * (If multiple entries were selected, don't
800 * touch the controls.) */
801 char *val = strchr(p, '\t');
802 if (val) {
803 int ind = 0;
804 val++;
805 while (ttymodes[ind]) {
806 if (strlen(ttymodes[ind]) == val-p-1 &&
807 !strncmp(ttymodes[ind], p, val-p-1))
808 break;
809 ind++;
810 }
811 dlg_listbox_select(td->modelist, dlg, ind);
812 dlg_radiobutton_set(td->valradio, dlg,
813 (*val == 'V'));
814 dlg_editbox_set(td->valbox, dlg, val+1);
815 }
816 }
c6ccd5c2 817 memmove(p, p+strlen(p)+1, len - (strlen(p)+1));
818 i++;
819 continue;
820 }
821 len -= strlen(p) + 1;
822 p += strlen(p) + 1;
823 i++;
824 }
825 memset(p, 0, lenof(cfg->ttymodes) - len);
826 dlg_refresh(td->listbox, dlg);
827 }
828 }
829}
830
fe8abbf4 831struct environ_data {
832 union control *varbox, *valbox, *addbutton, *rembutton, *listbox;
833};
834
835static void environ_handler(union control *ctrl, void *dlg,
836 void *data, int event)
837{
838 Config *cfg = (Config *)data;
839 struct environ_data *ed =
840 (struct environ_data *)ctrl->generic.context.p;
841
842 if (event == EVENT_REFRESH) {
843 if (ctrl == ed->listbox) {
844 char *p = cfg->environmt;
845 dlg_update_start(ctrl, dlg);
846 dlg_listbox_clear(ctrl, dlg);
847 while (*p) {
848 dlg_listbox_add(ctrl, dlg, p);
849 p += strlen(p) + 1;
850 }
851 dlg_update_done(ctrl, dlg);
852 }
853 } else if (event == EVENT_ACTION) {
854 if (ctrl == ed->addbutton) {
855 char str[sizeof(cfg->environmt)];
856 char *p;
857 dlg_editbox_get(ed->varbox, dlg, str, sizeof(str)-1);
858 if (!*str) {
859 dlg_beep(dlg);
860 return;
861 }
862 p = str + strlen(str);
863 *p++ = '\t';
864 dlg_editbox_get(ed->valbox, dlg, p, sizeof(str)-1 - (p - str));
865 if (!*p) {
866 dlg_beep(dlg);
867 return;
868 }
869 p = cfg->environmt;
870 while (*p) {
871 while (*p)
872 p++;
873 p++;
874 }
875 if ((p - cfg->environmt) + strlen(str) + 2 <
876 sizeof(cfg->environmt)) {
877 strcpy(p, str);
878 p[strlen(str) + 1] = '\0';
879 dlg_listbox_add(ed->listbox, dlg, str);
880 dlg_editbox_set(ed->varbox, dlg, "");
881 dlg_editbox_set(ed->valbox, dlg, "");
882 } else {
883 dlg_error_msg(dlg, "Environment too big");
884 }
885 } else if (ctrl == ed->rembutton) {
886 int i = dlg_listbox_index(ed->listbox, dlg);
887 if (i < 0) {
888 dlg_beep(dlg);
889 } else {
d9268a99 890 char *p, *q, *str;
fe8abbf4 891
892 dlg_listbox_del(ed->listbox, dlg, i);
893 p = cfg->environmt;
894 while (i > 0) {
895 if (!*p)
896 goto disaster;
897 while (*p)
898 p++;
899 p++;
900 i--;
901 }
902 q = p;
903 if (!*p)
904 goto disaster;
d9268a99 905 /* Populate controls with the entry we're about to delete
906 * for ease of editing */
907 str = p;
908 p = strchr(p, '\t');
909 if (!p)
910 goto disaster;
911 *p = '\0';
912 dlg_editbox_set(ed->varbox, dlg, str);
913 p++;
914 str = p;
915 dlg_editbox_set(ed->valbox, dlg, str);
916 p = strchr(p, '\0');
917 if (!p)
918 goto disaster;
fe8abbf4 919 p++;
920 while (*p) {
921 while (*p)
922 *q++ = *p++;
923 *q++ = *p++;
924 }
925 *q = '\0';
926 disaster:;
927 }
928 }
929 }
930}
931
932struct portfwd_data {
933 union control *addbutton, *rembutton, *listbox;
934 union control *sourcebox, *destbox, *direction;
89adc0e2 935#ifndef NO_IPV6
05581745 936 union control *addressfamily;
89adc0e2 937#endif
fe8abbf4 938};
939
940static void portfwd_handler(union control *ctrl, void *dlg,
941 void *data, int event)
942{
943 Config *cfg = (Config *)data;
944 struct portfwd_data *pfd =
945 (struct portfwd_data *)ctrl->generic.context.p;
946
947 if (event == EVENT_REFRESH) {
948 if (ctrl == pfd->listbox) {
949 char *p = cfg->portfwd;
950 dlg_update_start(ctrl, dlg);
951 dlg_listbox_clear(ctrl, dlg);
952 while (*p) {
953 dlg_listbox_add(ctrl, dlg, p);
954 p += strlen(p) + 1;
955 }
956 dlg_update_done(ctrl, dlg);
07e4d76d 957 } else if (ctrl == pfd->direction) {
958 /*
959 * Default is Local.
960 */
961 dlg_radiobutton_set(ctrl, dlg, 0);
89adc0e2 962#ifndef NO_IPV6
963 } else if (ctrl == pfd->addressfamily) {
05581745 964 dlg_radiobutton_set(ctrl, dlg, 0);
89adc0e2 965#endif
fe8abbf4 966 }
967 } else if (event == EVENT_ACTION) {
968 if (ctrl == pfd->addbutton) {
969 char str[sizeof(cfg->portfwd)];
970 char *p;
05581745 971 int i, type;
972 int whichbutton;
973
974 i = 0;
89adc0e2 975#ifndef NO_IPV6
05581745 976 whichbutton = dlg_radiobutton_get(pfd->addressfamily, dlg);
977 if (whichbutton == 1)
978 str[i++] = '4';
979 else if (whichbutton == 2)
980 str[i++] = '6';
89adc0e2 981#endif
05581745 982
983 whichbutton = dlg_radiobutton_get(pfd->direction, dlg);
820ebe3b 984 if (whichbutton == 0)
05581745 985 type = 'L';
820ebe3b 986 else if (whichbutton == 1)
05581745 987 type = 'R';
820ebe3b 988 else
05581745 989 type = 'D';
990 str[i++] = type;
991
992 dlg_editbox_get(pfd->sourcebox, dlg, str+i, sizeof(str) - i);
94042edc 993 if (!str[i]) {
fe8abbf4 994 dlg_error_msg(dlg, "You need to specify a source port number");
995 return;
996 }
997 p = str + strlen(str);
05581745 998 if (type != 'D') {
820ebe3b 999 *p++ = '\t';
1000 dlg_editbox_get(pfd->destbox, dlg, p,
e49c58ed 1001 sizeof(str) - (p - str));
820ebe3b 1002 if (!*p || !strchr(p, ':')) {
1003 dlg_error_msg(dlg,
1004 "You need to specify a destination address\n"
1005 "in the form \"host.name:port\"");
1006 return;
1007 }
1008 } else
1009 *p = '\0';
fe8abbf4 1010 p = cfg->portfwd;
1011 while (*p) {
1012 while (*p)
1013 p++;
1014 p++;
1015 }
e49c58ed 1016 if ((p - cfg->portfwd) + strlen(str) + 2 <=
fe8abbf4 1017 sizeof(cfg->portfwd)) {
1018 strcpy(p, str);
1019 p[strlen(str) + 1] = '\0';
1020 dlg_listbox_add(pfd->listbox, dlg, str);
1021 dlg_editbox_set(pfd->sourcebox, dlg, "");
1022 dlg_editbox_set(pfd->destbox, dlg, "");
1023 } else {
1024 dlg_error_msg(dlg, "Too many forwardings");
1025 }
1026 } else if (ctrl == pfd->rembutton) {
1027 int i = dlg_listbox_index(pfd->listbox, dlg);
1028 if (i < 0)
1029 dlg_beep(dlg);
1030 else {
d9268a99 1031 char *p, *q, *src, *dst;
1032 char dir;
fe8abbf4 1033
1034 dlg_listbox_del(pfd->listbox, dlg, i);
1035 p = cfg->portfwd;
1036 while (i > 0) {
1037 if (!*p)
1038 goto disaster2;
1039 while (*p)
1040 p++;
1041 p++;
1042 i--;
1043 }
1044 q = p;
1045 if (!*p)
1046 goto disaster2;
d9268a99 1047 /* Populate the controls with the entry we're about to
1048 * delete, for ease of editing. */
1049 {
1050 static const char *const afs = "A46";
1051 char *afp = strchr(afs, *p);
a97cd780 1052#ifndef NO_IPV6
d9268a99 1053 int idx = afp ? afp-afs : 0;
a97cd780 1054#endif
d9268a99 1055 if (afp)
1056 p++;
1057#ifndef NO_IPV6
1058 dlg_radiobutton_set(pfd->addressfamily, dlg, idx);
1059#endif
1060 }
1061 {
1062 static const char *const dirs = "LRD";
1063 dir = *p;
1064 dlg_radiobutton_set(pfd->direction, dlg,
1065 strchr(dirs, dir) - dirs);
1066 }
1067 p++;
1068 if (dir != 'D') {
1069 src = p;
1070 p = strchr(p, '\t');
1071 if (!p)
1072 goto disaster2;
1073 *p = '\0';
fe8abbf4 1074 p++;
d9268a99 1075 dst = p;
1076 } else {
1077 src = p;
1078 dst = "";
1079 }
1080 p = strchr(p, '\0');
1081 if (!p)
1082 goto disaster2;
1083 dlg_editbox_set(pfd->sourcebox, dlg, src);
1084 dlg_editbox_set(pfd->destbox, dlg, dst);
fe8abbf4 1085 p++;
1086 while (*p) {
1087 while (*p)
1088 *q++ = *p++;
1089 *q++ = *p++;
1090 }
1091 *q = '\0';
1092 disaster2:;
1093 }
1094 }
1095 }
1096}
1097
12745e35 1098void setup_config_box(struct controlbox *b, int midsession,
1099 int protocol, int protcfginfo)
fe8abbf4 1100{
1101 struct controlset *s;
1102 struct sessionsaver_data *ssd;
1103 struct charclass_data *ccd;
1104 struct colour_data *cd;
c6ccd5c2 1105 struct ttymodes_data *td;
fe8abbf4 1106 struct environ_data *ed;
1107 struct portfwd_data *pfd;
1108 union control *c;
f6f450e2 1109 char *str;
fe8abbf4 1110
1111 ssd = (struct sessionsaver_data *)
1112 ctrl_alloc(b, sizeof(struct sessionsaver_data));
56b9b9a7 1113 memset(ssd, 0, sizeof(*ssd));
2e155f47 1114 ssd->midsession = midsession;
fe8abbf4 1115
1116 /*
1117 * The standard panel that appears at the bottom of all panels:
1118 * Open, Cancel, Apply etc.
1119 */
1120 s = ctrl_getset(b, "", "", "");
1121 ctrl_columns(s, 5, 20, 20, 20, 20, 20);
1122 ssd->okbutton = ctrl_pushbutton(s,
1123 (midsession ? "Apply" : "Open"),
1124 (char)(midsession ? 'a' : 'o'),
1125 HELPCTX(no_help),
1126 sessionsaver_handler, P(ssd));
1127 ssd->okbutton->button.isdefault = TRUE;
1128 ssd->okbutton->generic.column = 3;
1129 ssd->cancelbutton = ctrl_pushbutton(s, "Cancel", 'c', HELPCTX(no_help),
1130 sessionsaver_handler, P(ssd));
0bd8d76d 1131 ssd->cancelbutton->button.iscancel = TRUE;
fe8abbf4 1132 ssd->cancelbutton->generic.column = 4;
1133 /* We carefully don't close the 5-column part, so that platform-
1134 * specific add-ons can put extra buttons alongside Open and Cancel. */
1135
1136 /*
1137 * The Session panel.
1138 */
f6f450e2 1139 str = dupprintf("Basic options for your %s session", appname);
1140 ctrl_settitle(b, "Session", str);
1141 sfree(str);
fe8abbf4 1142
1143 if (!midsession) {
7374c779 1144 struct hostport *hp = (struct hostport *)
1145 ctrl_alloc(b, sizeof(struct hostport));
7374c779 1146
fe8abbf4 1147 s = ctrl_getset(b, "Session", "hostport",
7374c779 1148 "Specify the destination you want to connect to");
fe8abbf4 1149 ctrl_columns(s, 2, 75, 25);
7374c779 1150 c = ctrl_editbox(s, HOST_BOX_TITLE, 'n', 100,
fe8abbf4 1151 HELPCTX(session_hostname),
7374c779 1152 config_host_handler, I(0), I(0));
fe8abbf4 1153 c->generic.column = 0;
7374c779 1154 hp->host = c;
1155 c = ctrl_editbox(s, PORT_BOX_TITLE, 'p', 100,
1156 HELPCTX(session_hostname),
1157 config_port_handler, I(0), I(0));
fe8abbf4 1158 c->generic.column = 1;
7374c779 1159 hp->port = c;
fe8abbf4 1160 ctrl_columns(s, 1, 100);
7374c779 1161
9e164d82 1162 if (!backend_from_proto(PROT_SSH)) {
7374c779 1163 ctrl_radiobuttons(s, "Connection type:", NO_SHORTCUT, 3,
fe8abbf4 1164 HELPCTX(session_hostname),
7374c779 1165 config_protocolbuttons_handler, P(hp),
fe8abbf4 1166 "Raw", 'r', I(PROT_RAW),
1167 "Telnet", 't', I(PROT_TELNET),
1168 "Rlogin", 'i', I(PROT_RLOGIN),
1169 NULL);
1170 } else {
7374c779 1171 ctrl_radiobuttons(s, "Connection type:", NO_SHORTCUT, 4,
fe8abbf4 1172 HELPCTX(session_hostname),
7374c779 1173 config_protocolbuttons_handler, P(hp),
fe8abbf4 1174 "Raw", 'r', I(PROT_RAW),
1175 "Telnet", 't', I(PROT_TELNET),
1176 "Rlogin", 'i', I(PROT_RLOGIN),
1177 "SSH", 's', I(PROT_SSH),
1178 NULL);
1179 }
fe8abbf4 1180 }
1181
48c4dd7c 1182 /*
1183 * The Load/Save panel is available even in mid-session.
1184 */
1185 s = ctrl_getset(b, "Session", "savedsessions",
59b8cd5a 1186 midsession ? "Save the current session settings" :
48c4dd7c 1187 "Load, save or delete a stored session");
1188 ctrl_columns(s, 2, 75, 25);
12745e35 1189 get_sesslist(&ssd->sesslist, TRUE);
48c4dd7c 1190 ssd->editbox = ctrl_editbox(s, "Saved Sessions", 'e', 100,
1191 HELPCTX(session_saved),
1192 sessionsaver_handler, P(ssd), P(NULL));
1193 ssd->editbox->generic.column = 0;
1194 /* Reset columns so that the buttons are alongside the list, rather
1195 * than alongside that edit box. */
1196 ctrl_columns(s, 1, 100);
1197 ctrl_columns(s, 2, 75, 25);
1198 ssd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1199 HELPCTX(session_saved),
1200 sessionsaver_handler, P(ssd));
1201 ssd->listbox->generic.column = 0;
1202 ssd->listbox->listbox.height = 7;
2e155f47 1203 if (!midsession) {
1204 ssd->loadbutton = ctrl_pushbutton(s, "Load", 'l',
1205 HELPCTX(session_saved),
1206 sessionsaver_handler, P(ssd));
1207 ssd->loadbutton->generic.column = 1;
1208 } else {
1209 /* We can't offer the Load button mid-session, as it would allow the
1210 * user to load and subsequently save settings they can't see. (And
1211 * also change otherwise immutable settings underfoot; that probably
1212 * shouldn't be a problem, but.) */
1213 ssd->loadbutton = NULL;
1214 }
1215 /* "Save" button is permitted mid-session. */
48c4dd7c 1216 ssd->savebutton = ctrl_pushbutton(s, "Save", 'v',
1217 HELPCTX(session_saved),
1218 sessionsaver_handler, P(ssd));
1219 ssd->savebutton->generic.column = 1;
2e155f47 1220 if (!midsession) {
1221 ssd->delbutton = ctrl_pushbutton(s, "Delete", 'd',
1222 HELPCTX(session_saved),
1223 sessionsaver_handler, P(ssd));
1224 ssd->delbutton->generic.column = 1;
1225 } else {
1226 /* Disable the Delete button mid-session too, for UI consistency. */
1227 ssd->delbutton = NULL;
1228 }
48c4dd7c 1229 ctrl_columns(s, 1, 100);
1230
fe8abbf4 1231 s = ctrl_getset(b, "Session", "otheropts", NULL);
1232 c = ctrl_radiobuttons(s, "Close window on exit:", 'w', 4,
1233 HELPCTX(session_coe),
1234 dlg_stdradiobutton_handler,
1235 I(offsetof(Config, close_on_exit)),
1236 "Always", I(FORCE_ON),
1237 "Never", I(FORCE_OFF),
1238 "Only on clean exit", I(AUTO), NULL);
1239
1240 /*
1241 * The Session/Logging panel.
1242 */
1243 ctrl_settitle(b, "Session/Logging", "Options controlling session logging");
1244
1245 s = ctrl_getset(b, "Session/Logging", "main", NULL);
3e547dd8 1246 /*
1247 * The logging buttons change depending on whether SSH packet
1248 * logging can sensibly be available.
1249 */
1250 {
bf8a49a1 1251 char *sshlogname, *sshrawlogname;
3e547dd8 1252 if ((midsession && protocol == PROT_SSH) ||
9e164d82 1253 (!midsession && backend_from_proto(PROT_SSH))) {
bf8a49a1 1254 sshlogname = "SSH packets";
1255 sshrawlogname = "SSH packets and raw data";
1256 } else {
1257 sshlogname = NULL; /* this will disable both buttons */
1258 sshrawlogname = NULL; /* this will just placate optimisers */
1259 }
1260 ctrl_radiobuttons(s, "Session logging:", NO_SHORTCUT, 2,
3e547dd8 1261 HELPCTX(logging_main),
17556692 1262 loggingbuttons_handler,
3e547dd8 1263 I(offsetof(Config, logtype)),
bf8a49a1 1264 "None", 't', I(LGTYP_NONE),
1265 "Printable output", 'p', I(LGTYP_ASCII),
1266 "All session output", 'l', I(LGTYP_DEBUG),
3e547dd8 1267 sshlogname, 's', I(LGTYP_PACKETS),
bf8a49a1 1268 sshrawlogname, 'r', I(LGTYP_SSHRAW),
3e547dd8 1269 NULL);
1270 }
fe8abbf4 1271 ctrl_filesel(s, "Log file name:", 'f',
1272 NULL, TRUE, "Select session log file name",
1273 HELPCTX(logging_filename),
1274 dlg_stdfilesel_handler, I(offsetof(Config, logfilename)));
1275 ctrl_text(s, "(Log file name can contain &Y, &M, &D for date,"
1276 " &T for time, and &H for host name)",
1277 HELPCTX(logging_filename));
1278 ctrl_radiobuttons(s, "What to do if the log file already exists:", 'e', 1,
1279 HELPCTX(logging_exists),
1280 dlg_stdradiobutton_handler, I(offsetof(Config,logxfovr)),
1281 "Always overwrite it", I(LGXF_OVR),
1282 "Always append to the end of it", I(LGXF_APN),
1283 "Ask the user every time", I(LGXF_ASK), NULL);
6d60c791 1284 ctrl_checkbox(s, "Flush log file frequently", 'u',
1285 HELPCTX(logging_flush),
1286 dlg_stdcheckbox_handler, I(offsetof(Config,logflush)));
fe8abbf4 1287
9a10ecf4 1288 if ((midsession && protocol == PROT_SSH) ||
9e164d82 1289 (!midsession && backend_from_proto(PROT_SSH))) {
9a10ecf4 1290 s = ctrl_getset(b, "Session/Logging", "ssh",
1291 "Options specific to SSH packet logging");
1292 ctrl_checkbox(s, "Omit known password fields", 'k',
1293 HELPCTX(logging_ssh_omit_password),
1294 dlg_stdcheckbox_handler, I(offsetof(Config,logomitpass)));
1295 ctrl_checkbox(s, "Omit session data", 'd',
1296 HELPCTX(logging_ssh_omit_data),
1297 dlg_stdcheckbox_handler, I(offsetof(Config,logomitdata)));
1298 }
1299
fe8abbf4 1300 /*
1301 * The Terminal panel.
1302 */
1303 ctrl_settitle(b, "Terminal", "Options controlling the terminal emulation");
1304
1305 s = ctrl_getset(b, "Terminal", "general", "Set various terminal options");
1306 ctrl_checkbox(s, "Auto wrap mode initially on", 'w',
1307 HELPCTX(terminal_autowrap),
1308 dlg_stdcheckbox_handler, I(offsetof(Config,wrap_mode)));
1309 ctrl_checkbox(s, "DEC Origin Mode initially on", 'd',
1310 HELPCTX(terminal_decom),
1311 dlg_stdcheckbox_handler, I(offsetof(Config,dec_om)));
1312 ctrl_checkbox(s, "Implicit CR in every LF", 'r',
1313 HELPCTX(terminal_lfhascr),
1314 dlg_stdcheckbox_handler, I(offsetof(Config,lfhascr)));
7612f22f 1315 ctrl_checkbox(s, "Implicit LF in every CR", 'f',
1316 HELPCTX(terminal_crhaslf),
1317 dlg_stdcheckbox_handler, I(offsetof(Config,crhaslf)));
fe8abbf4 1318 ctrl_checkbox(s, "Use background colour to erase screen", 'e',
1319 HELPCTX(terminal_bce),
1320 dlg_stdcheckbox_handler, I(offsetof(Config,bce)));
1321 ctrl_checkbox(s, "Enable blinking text", 'n',
1322 HELPCTX(terminal_blink),
1323 dlg_stdcheckbox_handler, I(offsetof(Config,blinktext)));
1324 ctrl_editbox(s, "Answerback to ^E:", 's', 100,
1325 HELPCTX(terminal_answerback),
1326 dlg_stdeditbox_handler, I(offsetof(Config,answerback)),
1327 I(sizeof(((Config *)0)->answerback)));
1328
1329 s = ctrl_getset(b, "Terminal", "ldisc", "Line discipline options");
1330 ctrl_radiobuttons(s, "Local echo:", 'l', 3,
1331 HELPCTX(terminal_localecho),
1332 dlg_stdradiobutton_handler,I(offsetof(Config,localecho)),
1333 "Auto", I(AUTO),
1334 "Force on", I(FORCE_ON),
1335 "Force off", I(FORCE_OFF), NULL);
1336 ctrl_radiobuttons(s, "Local line editing:", 't', 3,
1337 HELPCTX(terminal_localedit),
1338 dlg_stdradiobutton_handler,I(offsetof(Config,localedit)),
1339 "Auto", I(AUTO),
1340 "Force on", I(FORCE_ON),
1341 "Force off", I(FORCE_OFF), NULL);
1342
1343 s = ctrl_getset(b, "Terminal", "printing", "Remote-controlled printing");
1344 ctrl_combobox(s, "Printer to send ANSI printer output to:", 'p', 100,
1345 HELPCTX(terminal_printing),
1346 printerbox_handler, P(NULL), P(NULL));
1347
1348 /*
1349 * The Terminal/Keyboard panel.
1350 */
1351 ctrl_settitle(b, "Terminal/Keyboard",
1352 "Options controlling the effects of keys");
1353
1354 s = ctrl_getset(b, "Terminal/Keyboard", "mappings",
1355 "Change the sequences sent by:");
1356 ctrl_radiobuttons(s, "The Backspace key", 'b', 2,
1357 HELPCTX(keyboard_backspace),
1358 dlg_stdradiobutton_handler,
1359 I(offsetof(Config, bksp_is_delete)),
1360 "Control-H", I(0), "Control-? (127)", I(1), NULL);
1361 ctrl_radiobuttons(s, "The Home and End keys", 'e', 2,
1362 HELPCTX(keyboard_homeend),
1363 dlg_stdradiobutton_handler,
1364 I(offsetof(Config, rxvt_homeend)),
1365 "Standard", I(0), "rxvt", I(1), NULL);
1366 ctrl_radiobuttons(s, "The Function keys and keypad", 'f', 3,
1367 HELPCTX(keyboard_funkeys),
1368 dlg_stdradiobutton_handler,
1369 I(offsetof(Config, funky_type)),
1370 "ESC[n~", I(0), "Linux", I(1), "Xterm R6", I(2),
1371 "VT400", I(3), "VT100+", I(4), "SCO", I(5), NULL);
1372
1373 s = ctrl_getset(b, "Terminal/Keyboard", "appkeypad",
1374 "Application keypad settings:");
1375 ctrl_radiobuttons(s, "Initial state of cursor keys:", 'r', 3,
1376 HELPCTX(keyboard_appcursor),
1377 dlg_stdradiobutton_handler,
1378 I(offsetof(Config, app_cursor)),
1379 "Normal", I(0), "Application", I(1), NULL);
1380 ctrl_radiobuttons(s, "Initial state of numeric keypad:", 'n', 3,
1381 HELPCTX(keyboard_appkeypad),
1382 numeric_keypad_handler, P(NULL),
1383 "Normal", I(0), "Application", I(1), "NetHack", I(2),
1384 NULL);
1385
1386 /*
1387 * The Terminal/Bell panel.
1388 */
1389 ctrl_settitle(b, "Terminal/Bell",
1390 "Options controlling the terminal bell");
1391
1392 s = ctrl_getset(b, "Terminal/Bell", "style", "Set the style of bell");
1393 ctrl_radiobuttons(s, "Action to happen when a bell occurs:", 'b', 1,
1394 HELPCTX(bell_style),
1395 dlg_stdradiobutton_handler, I(offsetof(Config, beep)),
1396 "None (bell disabled)", I(BELL_DISABLED),
1397 "Make default system alert sound", I(BELL_DEFAULT),
1398 "Visual bell (flash window)", I(BELL_VISUAL), NULL);
1399
1400 s = ctrl_getset(b, "Terminal/Bell", "overload",
1401 "Control the bell overload behaviour");
1402 ctrl_checkbox(s, "Bell is temporarily disabled when over-used", 'd',
1403 HELPCTX(bell_overload),
1404 dlg_stdcheckbox_handler, I(offsetof(Config,bellovl)));
1405 ctrl_editbox(s, "Over-use means this many bells...", 'm', 20,
1406 HELPCTX(bell_overload),
1407 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_n)), I(-1));
1408 ctrl_editbox(s, "... in this many seconds", 't', 20,
1409 HELPCTX(bell_overload),
1410 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_t)),
62697e04 1411 I(-TICKSPERSEC));
fe8abbf4 1412 ctrl_text(s, "The bell is re-enabled after a few seconds of silence.",
1413 HELPCTX(bell_overload));
1414 ctrl_editbox(s, "Seconds of silence required", 's', 20,
1415 HELPCTX(bell_overload),
1416 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_s)),
62697e04 1417 I(-TICKSPERSEC));
fe8abbf4 1418
1419 /*
1420 * The Terminal/Features panel.
1421 */
1422 ctrl_settitle(b, "Terminal/Features",
1423 "Enabling and disabling advanced terminal features");
1424
1425 s = ctrl_getset(b, "Terminal/Features", "main", NULL);
1426 ctrl_checkbox(s, "Disable application cursor keys mode", 'u',
1427 HELPCTX(features_application),
1428 dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_c)));
1429 ctrl_checkbox(s, "Disable application keypad mode", 'k',
1430 HELPCTX(features_application),
1431 dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_k)));
1432 ctrl_checkbox(s, "Disable xterm-style mouse reporting", 'x',
1433 HELPCTX(features_mouse),
1434 dlg_stdcheckbox_handler, I(offsetof(Config,no_mouse_rep)));
1435 ctrl_checkbox(s, "Disable remote-controlled terminal resizing", 's',
1436 HELPCTX(features_resize),
1437 dlg_stdcheckbox_handler,
1438 I(offsetof(Config,no_remote_resize)));
1439 ctrl_checkbox(s, "Disable switching to alternate terminal screen", 'w',
1440 HELPCTX(features_altscreen),
1441 dlg_stdcheckbox_handler, I(offsetof(Config,no_alt_screen)));
1442 ctrl_checkbox(s, "Disable remote-controlled window title changing", 't',
1443 HELPCTX(features_retitle),
1444 dlg_stdcheckbox_handler,
1445 I(offsetof(Config,no_remote_wintitle)));
e65096f2 1446 ctrl_radiobuttons(s, "Response to remote title query (SECURITY):", 'q', 3,
1447 HELPCTX(features_qtitle),
1448 dlg_stdradiobutton_handler,
1449 I(offsetof(Config,remote_qtitle_action)),
1450 "None", I(TITLE_NONE),
1451 "Empty string", I(TITLE_EMPTY),
1452 "Window title", I(TITLE_REAL), NULL);
fe8abbf4 1453 ctrl_checkbox(s, "Disable destructive backspace on server sending ^?",'b',
1454 HELPCTX(features_dbackspace),
1455 dlg_stdcheckbox_handler, I(offsetof(Config,no_dbackspace)));
1456 ctrl_checkbox(s, "Disable remote-controlled character set configuration",
1457 'r', HELPCTX(features_charset), dlg_stdcheckbox_handler,
1458 I(offsetof(Config,no_remote_charset)));
f0fccd51 1459 ctrl_checkbox(s, "Disable Arabic text shaping",
f4ec0818 1460 'l', HELPCTX(features_arabicshaping), dlg_stdcheckbox_handler,
f0fccd51 1461 I(offsetof(Config, arabicshaping)));
1462 ctrl_checkbox(s, "Disable bidirectional text display",
f4ec0818 1463 'd', HELPCTX(features_bidi), dlg_stdcheckbox_handler,
f0fccd51 1464 I(offsetof(Config, bidi)));
fe8abbf4 1465
1466 /*
1467 * The Window panel.
1468 */
f6f450e2 1469 str = dupprintf("Options controlling %s's window", appname);
1470 ctrl_settitle(b, "Window", str);
1471 sfree(str);
fe8abbf4 1472
1473 s = ctrl_getset(b, "Window", "size", "Set the size of the window");
1474 ctrl_columns(s, 2, 50, 50);
fe8abbf4 1475 c = ctrl_editbox(s, "Columns", 'm', 100,
1476 HELPCTX(window_size),
1477 dlg_stdeditbox_handler, I(offsetof(Config,width)), I(-1));
b8e45023 1478 c->generic.column = 0;
1479 c = ctrl_editbox(s, "Rows", 'r', 100,
1480 HELPCTX(window_size),
1481 dlg_stdeditbox_handler, I(offsetof(Config,height)),I(-1));
fe8abbf4 1482 c->generic.column = 1;
1483 ctrl_columns(s, 1, 100);
1484
1485 s = ctrl_getset(b, "Window", "scrollback",
1486 "Control the scrollback in the window");
1487 ctrl_editbox(s, "Lines of scrollback", 's', 50,
1488 HELPCTX(window_scrollback),
1489 dlg_stdeditbox_handler, I(offsetof(Config,savelines)), I(-1));
1490 ctrl_checkbox(s, "Display scrollbar", 'd',
1491 HELPCTX(window_scrollback),
1492 dlg_stdcheckbox_handler, I(offsetof(Config,scrollbar)));
fe8abbf4 1493 ctrl_checkbox(s, "Reset scrollback on keypress", 'k',
1494 HELPCTX(window_scrollback),
1495 dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_key)));
1496 ctrl_checkbox(s, "Reset scrollback on display activity", 'p',
1497 HELPCTX(window_scrollback),
1498 dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_disp)));
876e5d5e 1499 ctrl_checkbox(s, "Push erased text into scrollback", 'e',
1500 HELPCTX(window_erased),
1501 dlg_stdcheckbox_handler,
1502 I(offsetof(Config,erase_to_scrollback)));
fe8abbf4 1503
1504 /*
1505 * The Window/Appearance panel.
1506 */
f6f450e2 1507 str = dupprintf("Configure the appearance of %s's window", appname);
1508 ctrl_settitle(b, "Window/Appearance", str);
1509 sfree(str);
fe8abbf4 1510
1511 s = ctrl_getset(b, "Window/Appearance", "cursor",
1512 "Adjust the use of the cursor");
1513 ctrl_radiobuttons(s, "Cursor appearance:", NO_SHORTCUT, 3,
1514 HELPCTX(appearance_cursor),
1515 dlg_stdradiobutton_handler,
1516 I(offsetof(Config, cursor_type)),
1517 "Block", 'l', I(0),
1518 "Underline", 'u', I(1),
1519 "Vertical line", 'v', I(2), NULL);
1520 ctrl_checkbox(s, "Cursor blinks", 'b',
1521 HELPCTX(appearance_cursor),
1522 dlg_stdcheckbox_handler, I(offsetof(Config,blink_cur)));
1523
1524 s = ctrl_getset(b, "Window/Appearance", "font",
1525 "Font settings");
1526 ctrl_fontsel(s, "Font used in the terminal window", 'n',
1527 HELPCTX(appearance_font),
1528 dlg_stdfontsel_handler, I(offsetof(Config, font)));
1529
1530 s = ctrl_getset(b, "Window/Appearance", "mouse",
1531 "Adjust the use of the mouse pointer");
1532 ctrl_checkbox(s, "Hide mouse pointer when typing in window", 'p',
1533 HELPCTX(appearance_hidemouse),
1534 dlg_stdcheckbox_handler, I(offsetof(Config,hide_mouseptr)));
1535
1536 s = ctrl_getset(b, "Window/Appearance", "border",
1537 "Adjust the window border");
b908db15 1538 ctrl_editbox(s, "Gap between text and window edge:", 'e', 20,
fe8abbf4 1539 HELPCTX(appearance_border),
1540 dlg_stdeditbox_handler,
1541 I(offsetof(Config,window_border)), I(-1));
1542
1543 /*
1544 * The Window/Behaviour panel.
1545 */
f6f450e2 1546 str = dupprintf("Configure the behaviour of %s's window", appname);
1547 ctrl_settitle(b, "Window/Behaviour", str);
1548 sfree(str);
fe8abbf4 1549
1550 s = ctrl_getset(b, "Window/Behaviour", "title",
1551 "Adjust the behaviour of the window title");
1552 ctrl_editbox(s, "Window title:", 't', 100,
1553 HELPCTX(appearance_title),
1554 dlg_stdeditbox_handler, I(offsetof(Config,wintitle)),
1555 I(sizeof(((Config *)0)->wintitle)));
1556 ctrl_checkbox(s, "Separate window and icon titles", 'i',
1557 HELPCTX(appearance_title),
1558 dlg_stdcheckbox_handler,
1559 I(CHECKBOX_INVERT | offsetof(Config,win_name_always)));
1560
1561 s = ctrl_getset(b, "Window/Behaviour", "main", NULL);
1562 ctrl_checkbox(s, "Warn before closing window", 'w',
1563 HELPCTX(behaviour_closewarn),
1564 dlg_stdcheckbox_handler, I(offsetof(Config,warn_on_close)));
1565
1566 /*
1567 * The Window/Translation panel.
1568 */
1569 ctrl_settitle(b, "Window/Translation",
1570 "Options controlling character set translation");
1571
1572 s = ctrl_getset(b, "Window/Translation", "trans",
1573 "Character set translation on received data");
1574 ctrl_combobox(s, "Received data assumed to be in which character set:",
1575 'r', 100, HELPCTX(translation_codepage),
1576 codepage_handler, P(NULL), P(NULL));
1577
74790953 1578 s = ctrl_getset(b, "Window/Translation", "tweaks", NULL);
1579 ctrl_checkbox(s, "Treat CJK ambiguous characters as wide", 'w',
1580 HELPCTX(translation_cjk_ambig_wide),
1581 dlg_stdcheckbox_handler, I(offsetof(Config,cjk_ambig_wide)));
1582
00381fc7 1583 str = dupprintf("Adjust how %s handles line drawing characters", appname);
f6f450e2 1584 s = ctrl_getset(b, "Window/Translation", "linedraw", str);
1585 sfree(str);
fe8abbf4 1586 ctrl_radiobuttons(s, "Handling of line drawing characters:", NO_SHORTCUT,1,
1587 HELPCTX(translation_linedraw),
1588 dlg_stdradiobutton_handler,
1589 I(offsetof(Config, vtmode)),
3900c2d6 1590 "Use Unicode line drawing code points",'u',I(VT_UNICODE),
fe8abbf4 1591 "Poor man's line drawing (+, - and |)",'p',I(VT_POORMAN),
3900c2d6 1592 NULL);
00381fc7 1593 ctrl_checkbox(s, "Copy and paste line drawing characters as lqqqk",'d',
1594 HELPCTX(selection_linedraw),
1595 dlg_stdcheckbox_handler, I(offsetof(Config,rawcnp)));
fe8abbf4 1596
1597 /*
1598 * The Window/Selection panel.
1599 */
1600 ctrl_settitle(b, "Window/Selection", "Options controlling copy and paste");
fe8abbf4 1601
1602 s = ctrl_getset(b, "Window/Selection", "mouse",
1603 "Control use of mouse");
1604 ctrl_checkbox(s, "Shift overrides application's use of mouse", 'p',
1605 HELPCTX(selection_shiftdrag),
1606 dlg_stdcheckbox_handler, I(offsetof(Config,mouse_override)));
1607 ctrl_radiobuttons(s,
1608 "Default selection mode (Alt+drag does the other one):",
1609 NO_SHORTCUT, 2,
1610 HELPCTX(selection_rect),
1611 dlg_stdradiobutton_handler,
1612 I(offsetof(Config, rect_select)),
1613 "Normal", 'n', I(0),
1614 "Rectangular block", 'r', I(1), NULL);
1615
1616 s = ctrl_getset(b, "Window/Selection", "charclass",
1617 "Control the select-one-word-at-a-time mode");
1618 ccd = (struct charclass_data *)
1619 ctrl_alloc(b, sizeof(struct charclass_data));
1620 ccd->listbox = ctrl_listbox(s, "Character classes:", 'e',
1621 HELPCTX(selection_charclasses),
1622 charclass_handler, P(ccd));
1623 ccd->listbox->listbox.multisel = 1;
1624 ccd->listbox->listbox.ncols = 4;
3d88e64d 1625 ccd->listbox->listbox.percentages = snewn(4, int);
fe8abbf4 1626 ccd->listbox->listbox.percentages[0] = 15;
1627 ccd->listbox->listbox.percentages[1] = 25;
1628 ccd->listbox->listbox.percentages[2] = 20;
1629 ccd->listbox->listbox.percentages[3] = 40;
1630 ctrl_columns(s, 2, 67, 33);
1631 ccd->editbox = ctrl_editbox(s, "Set to class", 't', 50,
1632 HELPCTX(selection_charclasses),
1633 charclass_handler, P(ccd), P(NULL));
1634 ccd->editbox->generic.column = 0;
1635 ccd->button = ctrl_pushbutton(s, "Set", 's',
1636 HELPCTX(selection_charclasses),
1637 charclass_handler, P(ccd));
1638 ccd->button->generic.column = 1;
1639 ctrl_columns(s, 1, 100);
1640
1641 /*
1642 * The Window/Colours panel.
1643 */
1644 ctrl_settitle(b, "Window/Colours", "Options controlling use of colours");
1645
1646 s = ctrl_getset(b, "Window/Colours", "general",
1647 "General options for colour usage");
c6f1b8ed 1648 ctrl_checkbox(s, "Allow terminal to specify ANSI colours", 'i',
1649 HELPCTX(colours_ansi),
1650 dlg_stdcheckbox_handler, I(offsetof(Config,ansi_colour)));
cecb13f6 1651 ctrl_checkbox(s, "Allow terminal to use xterm 256-colour mode", '2',
1652 HELPCTX(colours_xterm256), dlg_stdcheckbox_handler,
1653 I(offsetof(Config,xterm_256_colour)));
fe8abbf4 1654 ctrl_checkbox(s, "Bolded text is a different colour", 'b',
1655 HELPCTX(colours_bold),
1656 dlg_stdcheckbox_handler, I(offsetof(Config,bold_colour)));
1657
f6f450e2 1658 str = dupprintf("Adjust the precise colours %s displays", appname);
1659 s = ctrl_getset(b, "Window/Colours", "adjust", str);
1660 sfree(str);
fe8abbf4 1661 ctrl_text(s, "Select a colour from the list, and then click the"
1662 " Modify button to change its appearance.",
1663 HELPCTX(colours_config));
1664 ctrl_columns(s, 2, 67, 33);
1665 cd = (struct colour_data *)ctrl_alloc(b, sizeof(struct colour_data));
1666 cd->listbox = ctrl_listbox(s, "Select a colour to adjust:", 'u',
1667 HELPCTX(colours_config), colour_handler, P(cd));
1668 cd->listbox->generic.column = 0;
18c2f87c 1669 cd->listbox->listbox.height = 7;
fe8abbf4 1670 c = ctrl_text(s, "RGB value:", HELPCTX(colours_config));
1671 c->generic.column = 1;
18c2f87c 1672 cd->redit = ctrl_editbox(s, "Red", 'r', 50, HELPCTX(colours_config),
1673 colour_handler, P(cd), P(NULL));
1674 cd->redit->generic.column = 1;
1675 cd->gedit = ctrl_editbox(s, "Green", 'n', 50, HELPCTX(colours_config),
1676 colour_handler, P(cd), P(NULL));
1677 cd->gedit->generic.column = 1;
1678 cd->bedit = ctrl_editbox(s, "Blue", 'e', 50, HELPCTX(colours_config),
1679 colour_handler, P(cd), P(NULL));
1680 cd->bedit->generic.column = 1;
fe8abbf4 1681 cd->button = ctrl_pushbutton(s, "Modify", 'm', HELPCTX(colours_config),
1682 colour_handler, P(cd));
1683 cd->button->generic.column = 1;
1684 ctrl_columns(s, 1, 100);
1685
1686 /*
3e547dd8 1687 * The Connection panel. This doesn't show up if we're in a
1688 * non-network utility such as pterm. We tell this by being
1689 * passed a protocol < 0.
fe8abbf4 1690 */
3e547dd8 1691 if (protocol >= 0) {
1692 ctrl_settitle(b, "Connection", "Options controlling the connection");
1693
05581745 1694 s = ctrl_getset(b, "Connection", "keepalive",
1695 "Sending of null packets to keep session active");
1696 ctrl_editbox(s, "Seconds between keepalives (0 to turn off)", 'k', 20,
1697 HELPCTX(connection_keepalive),
1698 dlg_stdeditbox_handler, I(offsetof(Config,ping_interval)),
1699 I(-1));
1700
3e547dd8 1701 if (!midsession) {
05581745 1702 s = ctrl_getset(b, "Connection", "tcp",
1703 "Low-level TCP connection options");
1704 ctrl_checkbox(s, "Disable Nagle's algorithm (TCP_NODELAY option)",
1705 'n', HELPCTX(connection_nodelay),
1706 dlg_stdcheckbox_handler,
1707 I(offsetof(Config,tcp_nodelay)));
1708 ctrl_checkbox(s, "Enable TCP keepalives (SO_KEEPALIVE option)",
1709 'p', HELPCTX(connection_tcpkeepalive),
1710 dlg_stdcheckbox_handler,
1711 I(offsetof(Config,tcp_keepalives)));
22db244f 1712#ifndef NO_IPV6
05581745 1713 s = ctrl_getset(b, "Connection", "ipversion",
1714 "Internet protocol version");
22db244f 1715 ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
05581745 1716 HELPCTX(connection_ipversion),
1717 dlg_stdradiobutton_handler,
1718 I(offsetof(Config, addressfamily)),
b908db15 1719 "Auto", 'u', I(ADDRTYPE_UNSPEC),
1720 "IPv4", '4', I(ADDRTYPE_IPV4),
1721 "IPv6", '6', I(ADDRTYPE_IPV6),
05581745 1722 NULL);
22db244f 1723#endif
881da168 1724
1725 s = ctrl_getset(b, "Connection", "identity",
1726 "Logical name of remote host");
1727 ctrl_editbox(s, "Logical name of remote host (e.g. for SSH key lookup):",
1728 'm', 100,
1729 HELPCTX(connection_loghost),
1730 dlg_stdeditbox_handler, I(offsetof(Config,loghost)),
1731 I(sizeof(((Config *)0)->loghost)));
05581745 1732 }
1733
1734 /*
1735 * A sub-panel Connection/Data, containing options that
1736 * decide on data to send to the server.
1737 */
1738 if (!midsession) {
1739 ctrl_settitle(b, "Connection/Data", "Data to send to the server");
1740
1741 s = ctrl_getset(b, "Connection/Data", "login",
1742 "Login details");
1743 ctrl_editbox(s, "Auto-login username", 'u', 50,
1744 HELPCTX(connection_username),
1745 dlg_stdeditbox_handler, I(offsetof(Config,username)),
1746 I(sizeof(((Config *)0)->username)));
1747
1748 s = ctrl_getset(b, "Connection/Data", "term",
1749 "Terminal details");
3e547dd8 1750 ctrl_editbox(s, "Terminal-type string", 't', 50,
1751 HELPCTX(connection_termtype),
1752 dlg_stdeditbox_handler, I(offsetof(Config,termtype)),
1753 I(sizeof(((Config *)0)->termtype)));
a5dd8467 1754 ctrl_editbox(s, "Terminal speeds", 's', 50,
1755 HELPCTX(connection_termspeed),
1756 dlg_stdeditbox_handler, I(offsetof(Config,termspeed)),
1757 I(sizeof(((Config *)0)->termspeed)));
73feed4f 1758
05581745 1759 s = ctrl_getset(b, "Connection/Data", "env",
1760 "Environment variables");
73feed4f 1761 ctrl_columns(s, 2, 80, 20);
1762 ed = (struct environ_data *)
1763 ctrl_alloc(b, sizeof(struct environ_data));
1764 ed->varbox = ctrl_editbox(s, "Variable", 'v', 60,
1765 HELPCTX(telnet_environ),
1766 environ_handler, P(ed), P(NULL));
1767 ed->varbox->generic.column = 0;
1768 ed->valbox = ctrl_editbox(s, "Value", 'l', 60,
1769 HELPCTX(telnet_environ),
1770 environ_handler, P(ed), P(NULL));
1771 ed->valbox->generic.column = 0;
1772 ed->addbutton = ctrl_pushbutton(s, "Add", 'd',
1773 HELPCTX(telnet_environ),
1774 environ_handler, P(ed));
1775 ed->addbutton->generic.column = 1;
1776 ed->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1777 HELPCTX(telnet_environ),
1778 environ_handler, P(ed));
1779 ed->rembutton->generic.column = 1;
1780 ctrl_columns(s, 1, 100);
1781 ed->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1782 HELPCTX(telnet_environ),
1783 environ_handler, P(ed));
1784 ed->listbox->listbox.height = 3;
1785 ed->listbox->listbox.ncols = 2;
1786 ed->listbox->listbox.percentages = snewn(2, int);
1787 ed->listbox->listbox.percentages[0] = 30;
1788 ed->listbox->listbox.percentages[1] = 70;
3e547dd8 1789 }
fe8abbf4 1790
fe8abbf4 1791 }
1792
1793 if (!midsession) {
1794 /*
1795 * The Connection/Proxy panel.
1796 */
1797 ctrl_settitle(b, "Connection/Proxy",
1798 "Options controlling proxy usage");
1799
10068a0b 1800 s = ctrl_getset(b, "Connection/Proxy", "basics", NULL);
1801 ctrl_radiobuttons(s, "Proxy type:", 't', 3,
fe8abbf4 1802 HELPCTX(proxy_type),
1803 dlg_stdradiobutton_handler,
1804 I(offsetof(Config, proxy_type)),
0f0a2507 1805 "None", I(PROXY_NONE),
10068a0b 1806 "SOCKS 4", I(PROXY_SOCKS4),
1807 "SOCKS 5", I(PROXY_SOCKS5),
0f0a2507 1808 "HTTP", I(PROXY_HTTP),
0f0a2507 1809 "Telnet", I(PROXY_TELNET),
fe8abbf4 1810 NULL);
1811 ctrl_columns(s, 2, 80, 20);
1812 c = ctrl_editbox(s, "Proxy hostname", 'y', 100,
1813 HELPCTX(proxy_main),
1814 dlg_stdeditbox_handler,
1815 I(offsetof(Config,proxy_host)),
1816 I(sizeof(((Config *)0)->proxy_host)));
1817 c->generic.column = 0;
1818 c = ctrl_editbox(s, "Port", 'p', 100,
1819 HELPCTX(proxy_main),
1820 dlg_stdeditbox_handler,
1821 I(offsetof(Config,proxy_port)),
1822 I(-1));
1823 c->generic.column = 1;
1824 ctrl_columns(s, 1, 100);
1825 ctrl_editbox(s, "Exclude Hosts/IPs", 'e', 100,
1826 HELPCTX(proxy_exclude),
1827 dlg_stdeditbox_handler,
1828 I(offsetof(Config,proxy_exclude_list)),
1829 I(sizeof(((Config *)0)->proxy_exclude_list)));
1830 ctrl_checkbox(s, "Consider proxying local host connections", 'x',
1831 HELPCTX(proxy_exclude),
1832 dlg_stdcheckbox_handler,
1833 I(offsetof(Config,even_proxy_localhost)));
1834 ctrl_radiobuttons(s, "Do DNS name lookup at proxy end:", 'd', 3,
1835 HELPCTX(proxy_dns),
1836 dlg_stdradiobutton_handler,
1837 I(offsetof(Config, proxy_dns)),
1838 "No", I(FORCE_OFF),
1839 "Auto", I(AUTO),
1840 "Yes", I(FORCE_ON), NULL);
1841 ctrl_editbox(s, "Username", 'u', 60,
1842 HELPCTX(proxy_auth),
1843 dlg_stdeditbox_handler,
1844 I(offsetof(Config,proxy_username)),
1845 I(sizeof(((Config *)0)->proxy_username)));
1846 c = ctrl_editbox(s, "Password", 'w', 60,
1847 HELPCTX(proxy_auth),
1848 dlg_stdeditbox_handler,
1849 I(offsetof(Config,proxy_password)),
1850 I(sizeof(((Config *)0)->proxy_password)));
1851 c->editbox.password = 1;
fe8abbf4 1852 ctrl_editbox(s, "Telnet command", 'm', 100,
1853 HELPCTX(proxy_command),
1854 dlg_stdeditbox_handler,
1855 I(offsetof(Config,proxy_telnet_command)),
1856 I(sizeof(((Config *)0)->proxy_telnet_command)));
fe8abbf4 1857 }
1858
1859 /*
1860 * The Telnet panel exists in the base config box, and in a
1861 * mid-session reconfig box _if_ we're using Telnet.
1862 */
1863 if (!midsession || protocol == PROT_TELNET) {
1864 /*
1865 * The Connection/Telnet panel.
1866 */
1867 ctrl_settitle(b, "Connection/Telnet",
1868 "Options controlling Telnet connections");
1869
fe8abbf4 1870 s = ctrl_getset(b, "Connection/Telnet", "protocol",
1871 "Telnet protocol adjustments");
1872
1873 if (!midsession) {
1874 ctrl_radiobuttons(s, "Handling of OLD_ENVIRON ambiguity:",
1875 NO_SHORTCUT, 2,
1876 HELPCTX(telnet_oldenviron),
1877 dlg_stdradiobutton_handler,
1878 I(offsetof(Config, rfc_environ)),
1879 "BSD (commonplace)", 'b', I(0),
1880 "RFC 1408 (unusual)", 'f', I(1), NULL);
1881 ctrl_radiobuttons(s, "Telnet negotiation mode:", 't', 2,
1882 HELPCTX(telnet_passive),
1883 dlg_stdradiobutton_handler,
1884 I(offsetof(Config, passive_telnet)),
1885 "Passive", I(1), "Active", I(0), NULL);
1886 }
76d3d354 1887 ctrl_checkbox(s, "Keyboard sends Telnet special commands", 'k',
fe8abbf4 1888 HELPCTX(telnet_specialkeys),
1889 dlg_stdcheckbox_handler,
1890 I(offsetof(Config,telnet_keyboard)));
76d3d354 1891 ctrl_checkbox(s, "Return key sends Telnet New Line instead of ^M",
1892 'm', HELPCTX(telnet_newline),
fe8abbf4 1893 dlg_stdcheckbox_handler,
1894 I(offsetof(Config,telnet_newline)));
1895 }
1896
1897 if (!midsession) {
1898
1899 /*
1900 * The Connection/Rlogin panel.
1901 */
1902 ctrl_settitle(b, "Connection/Rlogin",
1903 "Options controlling Rlogin connections");
1904
1905 s = ctrl_getset(b, "Connection/Rlogin", "data",
1906 "Data to send to the server");
fe8abbf4 1907 ctrl_editbox(s, "Local username:", 'l', 50,
1908 HELPCTX(rlogin_localuser),
1909 dlg_stdeditbox_handler, I(offsetof(Config,localusername)),
1910 I(sizeof(((Config *)0)->localusername)));
1911
1912 }
1913
1914 /*
fda2feb1 1915 * All the SSH stuff is omitted in PuTTYtel, or in a reconfig
1916 * when we're not doing SSH.
fe8abbf4 1917 */
1918
9e164d82 1919 if (backend_from_proto(PROT_SSH) && (!midsession || protocol == PROT_SSH)) {
fe8abbf4 1920
1921 /*
1922 * The Connection/SSH panel.
1923 */
1924 ctrl_settitle(b, "Connection/SSH",
1925 "Options controlling SSH connections");
1926
e13bba36 1927 if (midsession && protcfginfo == 1) {
fda2feb1 1928 s = ctrl_getset(b, "Connection/SSH", "disclaimer", NULL);
1929 ctrl_text(s, "Nothing on this panel may be reconfigured in mid-"
1930 "session; it is only here so that sub-panels of it can "
1931 "exist without looking strange.", HELPCTX(no_help));
1932 }
1933
1934 if (!midsession) {
1935
1936 s = ctrl_getset(b, "Connection/SSH", "data",
1937 "Data to send to the server");
1938 ctrl_editbox(s, "Remote command:", 'r', 100,
1939 HELPCTX(ssh_command),
1940 dlg_stdeditbox_handler, I(offsetof(Config,remote_cmd)),
1941 I(sizeof(((Config *)0)->remote_cmd)));
1942
1943 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
fda2feb1 1944 ctrl_checkbox(s, "Don't start a shell or command at all", 'n',
1945 HELPCTX(ssh_noshell),
1946 dlg_stdcheckbox_handler,
1947 I(offsetof(Config,ssh_no_shell)));
e13bba36 1948 }
1949
1950 if (!midsession || protcfginfo != 1) {
1951 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1952
fda2feb1 1953 ctrl_checkbox(s, "Enable compression", 'e',
1954 HELPCTX(ssh_compress),
1955 dlg_stdcheckbox_handler,
1956 I(offsetof(Config,compression)));
e13bba36 1957 }
1958
1959 if (!midsession) {
1960 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1961
fda2feb1 1962 ctrl_radiobuttons(s, "Preferred SSH protocol version:", NO_SHORTCUT, 4,
1963 HELPCTX(ssh_protocol),
1964 dlg_stdradiobutton_handler,
1965 I(offsetof(Config, sshprot)),
1966 "1 only", 'l', I(0),
1967 "1", '1', I(1),
1968 "2", '2', I(2),
1969 "2 only", 'y', I(3), NULL);
e13bba36 1970 }
fda2feb1 1971
e13bba36 1972 if (!midsession || protcfginfo != 1) {
fda2feb1 1973 s = ctrl_getset(b, "Connection/SSH", "encryption", "Encryption options");
1974 c = ctrl_draglist(s, "Encryption cipher selection policy:", 's',
1975 HELPCTX(ssh_ciphers),
1976 cipherlist_handler, P(NULL));
1977 c->listbox.height = 6;
1978
2e85c969 1979 ctrl_checkbox(s, "Enable legacy use of single-DES in SSH-2", 'i',
bb524800 1980 HELPCTX(ssh_ciphers),
fda2feb1 1981 dlg_stdcheckbox_handler,
1982 I(offsetof(Config,ssh2_des_cbc)));
e6c1536e 1983 }
fe8abbf4 1984
e6c1536e 1985 /*
1986 * The Connection/SSH/Kex panel. (Owing to repeat key
f89c3294 1987 * exchange, this is all meaningful in mid-session _if_
2e85c969 1988 * we're using SSH-2 or haven't decided yet.)
e6c1536e 1989 */
f89c3294 1990 if (protcfginfo != 1) {
1991 ctrl_settitle(b, "Connection/SSH/Kex",
1992 "Options controlling SSH key exchange");
1993
1994 s = ctrl_getset(b, "Connection/SSH/Kex", "main",
1995 "Key exchange algorithm options");
2e077f2e 1996 c = ctrl_draglist(s, "Algorithm selection policy:", 's',
f89c3294 1997 HELPCTX(ssh_kexlist),
1998 kexlist_handler, P(NULL));
1999 c->listbox.height = 5;
2000
2001 s = ctrl_getset(b, "Connection/SSH/Kex", "repeat",
2002 "Options controlling key re-exchange");
2003
2004 ctrl_editbox(s, "Max minutes before rekey (0 for no limit)", 't', 20,
2005 HELPCTX(ssh_kex_repeat),
2006 dlg_stdeditbox_handler,
2007 I(offsetof(Config,ssh_rekey_time)),
2008 I(-1));
2009 ctrl_editbox(s, "Max data before rekey (0 for no limit)", 'x', 20,
2010 HELPCTX(ssh_kex_repeat),
2011 dlg_stdeditbox_handler,
2012 I(offsetof(Config,ssh_rekey_data)),
2013 I(16));
2014 ctrl_text(s, "(Use 1M for 1 megabyte, 1G for 1 gigabyte etc)",
2015 HELPCTX(ssh_kex_repeat));
2016 }
e6c1536e 2017
2018 if (!midsession) {
83e7d008 2019
fda2feb1 2020 /*
2021 * The Connection/SSH/Auth panel.
2022 */
2023 ctrl_settitle(b, "Connection/SSH/Auth",
2024 "Options controlling SSH authentication");
fe8abbf4 2025
a1a1fae4 2026 s = ctrl_getset(b, "Connection/SSH/Auth", "main", NULL);
2027 ctrl_checkbox(s, "Bypass authentication entirely (SSH-2 only)", 'b',
2028 HELPCTX(ssh_auth_bypass),
2029 dlg_stdcheckbox_handler,
2030 I(offsetof(Config,ssh_no_userauth)));
2031
fda2feb1 2032 s = ctrl_getset(b, "Connection/SSH/Auth", "methods",
2033 "Authentication methods");
973612f5 2034 ctrl_checkbox(s, "Attempt authentication using Pageant", 'p',
2035 HELPCTX(ssh_auth_pageant),
2036 dlg_stdcheckbox_handler,
2037 I(offsetof(Config,tryagent)));
2e85c969 2038 ctrl_checkbox(s, "Attempt TIS or CryptoCard auth (SSH-1)", 'm',
fda2feb1 2039 HELPCTX(ssh_auth_tis),
2040 dlg_stdcheckbox_handler,
2041 I(offsetof(Config,try_tis_auth)));
2e85c969 2042 ctrl_checkbox(s, "Attempt \"keyboard-interactive\" auth (SSH-2)",
fda2feb1 2043 'i', HELPCTX(ssh_auth_ki),
2044 dlg_stdcheckbox_handler,
2045 I(offsetof(Config,try_ki_auth)));
2046
2047 s = ctrl_getset(b, "Connection/SSH/Auth", "params",
2048 "Authentication parameters");
2049 ctrl_checkbox(s, "Allow agent forwarding", 'f',
2050 HELPCTX(ssh_auth_agentfwd),
2051 dlg_stdcheckbox_handler, I(offsetof(Config,agentfwd)));
2e85c969 2052 ctrl_checkbox(s, "Allow attempted changes of username in SSH-2", 'u',
fda2feb1 2053 HELPCTX(ssh_auth_changeuser),
2054 dlg_stdcheckbox_handler,
2055 I(offsetof(Config,change_username)));
2056 ctrl_filesel(s, "Private key file for authentication:", 'k',
2057 FILTER_KEY_FILES, FALSE, "Select private key file",
2058 HELPCTX(ssh_auth_privkey),
2059 dlg_stdfilesel_handler, I(offsetof(Config, keyfile)));
2060 }
fe8abbf4 2061
fda2feb1 2062 if (!midsession) {
05581745 2063 /*
c6ccd5c2 2064 * The Connection/SSH/TTY panel.
2065 */
2066 ctrl_settitle(b, "Connection/SSH/TTY", "Remote terminal settings");
2067
2068 s = ctrl_getset(b, "Connection/SSH/TTY", "sshtty", NULL);
2069 ctrl_checkbox(s, "Don't allocate a pseudo-terminal", 'p',
2070 HELPCTX(ssh_nopty),
2071 dlg_stdcheckbox_handler,
2072 I(offsetof(Config,nopty)));
2073
2074 s = ctrl_getset(b, "Connection/SSH/TTY", "ttymodes",
2075 "Terminal modes");
2076 td = (struct ttymodes_data *)
2077 ctrl_alloc(b, sizeof(struct ttymodes_data));
2078 ctrl_columns(s, 2, 75, 25);
2079 c = ctrl_text(s, "Terminal modes to send:", HELPCTX(ssh_ttymodes));
2080 c->generic.column = 0;
2081 td->rembutton = ctrl_pushbutton(s, "Remove", 'r',
2082 HELPCTX(ssh_ttymodes),
2083 ttymodes_handler, P(td));
2084 td->rembutton->generic.column = 1;
2085 td->rembutton->generic.tabdelay = 1;
2086 ctrl_columns(s, 1, 100);
2087 td->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
2088 HELPCTX(ssh_ttymodes),
2089 ttymodes_handler, P(td));
2090 td->listbox->listbox.multisel = 1;
2091 td->listbox->listbox.height = 4;
2092 td->listbox->listbox.ncols = 2;
2093 td->listbox->listbox.percentages = snewn(2, int);
2094 td->listbox->listbox.percentages[0] = 40;
2095 td->listbox->listbox.percentages[1] = 60;
2096 ctrl_tabdelay(s, td->rembutton);
2097 ctrl_columns(s, 2, 75, 25);
2098 td->modelist = ctrl_droplist(s, "Mode:", 'm', 67,
2099 HELPCTX(ssh_ttymodes),
2100 ttymodes_handler, P(td));
2101 td->modelist->generic.column = 0;
2102 td->addbutton = ctrl_pushbutton(s, "Add", 'd',
2103 HELPCTX(ssh_ttymodes),
2104 ttymodes_handler, P(td));
2105 td->addbutton->generic.column = 1;
2106 td->addbutton->generic.tabdelay = 1;
2107 ctrl_columns(s, 1, 100); /* column break */
2108 /* Bit of a hack to get the value radio buttons and
2109 * edit-box on the same row. */
2110 ctrl_columns(s, 3, 25, 50, 25);
2111 c = ctrl_text(s, "Value:", HELPCTX(ssh_ttymodes));
2112 c->generic.column = 0;
2113 td->valradio = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 2,
2114 HELPCTX(ssh_ttymodes),
2115 ttymodes_handler, P(td),
2116 "Auto", NO_SHORTCUT, P(NULL),
2117 "This:", NO_SHORTCUT, P(NULL),
2118 NULL);
2119 td->valradio->generic.column = 1;
2120 td->valbox = ctrl_editbox(s, NULL, NO_SHORTCUT, 100,
2121 HELPCTX(ssh_ttymodes),
2122 ttymodes_handler, P(td), P(NULL));
2123 td->valbox->generic.column = 2;
2124 ctrl_tabdelay(s, td->addbutton);
2125
2126 }
2127
2128 if (!midsession) {
2129 /*
05581745 2130 * The Connection/SSH/X11 panel.
2131 */
2132 ctrl_settitle(b, "Connection/SSH/X11",
2133 "Options controlling SSH X11 forwarding");
2134
2135 s = ctrl_getset(b, "Connection/SSH/X11", "x11", "X11 forwarding");
fda2feb1 2136 ctrl_checkbox(s, "Enable X11 forwarding", 'e',
2137 HELPCTX(ssh_tunnels_x11),
2138 dlg_stdcheckbox_handler,I(offsetof(Config,x11_forward)));
2139 ctrl_editbox(s, "X display location", 'x', 50,
2140 HELPCTX(ssh_tunnels_x11),
2141 dlg_stdeditbox_handler, I(offsetof(Config,x11_display)),
2142 I(sizeof(((Config *)0)->x11_display)));
2143 ctrl_radiobuttons(s, "Remote X11 authentication protocol", 'u', 2,
2144 HELPCTX(ssh_tunnels_x11auth),
2145 dlg_stdradiobutton_handler,
2146 I(offsetof(Config, x11_auth)),
2147 "MIT-Magic-Cookie-1", I(X11_MIT),
2148 "XDM-Authorization-1", I(X11_XDM), NULL);
2149 }
fe8abbf4 2150
05581745 2151 /*
2152 * The Tunnels panel _is_ still available in mid-session.
2153 */
2154 ctrl_settitle(b, "Connection/SSH/Tunnels",
2155 "Options controlling SSH port forwarding");
2156
fe8abbf4 2157 s = ctrl_getset(b, "Connection/SSH/Tunnels", "portfwd",
2158 "Port forwarding");
2159 ctrl_checkbox(s, "Local ports accept connections from other hosts",'t',
2160 HELPCTX(ssh_tunnels_portfwd_localhost),
2161 dlg_stdcheckbox_handler,
2162 I(offsetof(Config,lport_acceptall)));
2e85c969 2163 ctrl_checkbox(s, "Remote ports do the same (SSH-2 only)", 'p',
fe8abbf4 2164 HELPCTX(ssh_tunnels_portfwd_localhost),
2165 dlg_stdcheckbox_handler,
2166 I(offsetof(Config,rport_acceptall)));
2167
2168 ctrl_columns(s, 3, 55, 20, 25);
2169 c = ctrl_text(s, "Forwarded ports:", HELPCTX(ssh_tunnels_portfwd));
2170 c->generic.column = COLUMN_FIELD(0,2);
2171 /* You want to select from the list, _then_ hit Remove. So tab order
2172 * should be that way round. */
2173 pfd = (struct portfwd_data *)ctrl_alloc(b,sizeof(struct portfwd_data));
2174 pfd->rembutton = ctrl_pushbutton(s, "Remove", 'r',
2175 HELPCTX(ssh_tunnels_portfwd),
2176 portfwd_handler, P(pfd));
2177 pfd->rembutton->generic.column = 2;
2178 pfd->rembutton->generic.tabdelay = 1;
2179 pfd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
2180 HELPCTX(ssh_tunnels_portfwd),
2181 portfwd_handler, P(pfd));
2182 pfd->listbox->listbox.height = 3;
37dbf11c 2183 pfd->listbox->listbox.ncols = 2;
3d88e64d 2184 pfd->listbox->listbox.percentages = snewn(2, int);
37dbf11c 2185 pfd->listbox->listbox.percentages[0] = 20;
2186 pfd->listbox->listbox.percentages[1] = 80;
fe8abbf4 2187 ctrl_tabdelay(s, pfd->rembutton);
2188 ctrl_text(s, "Add new forwarded port:", HELPCTX(ssh_tunnels_portfwd));
2189 /* You want to enter source, destination and type, _then_ hit Add.
2190 * Again, we adjust the tab order to reflect this. */
2191 pfd->addbutton = ctrl_pushbutton(s, "Add", 'd',
2192 HELPCTX(ssh_tunnels_portfwd),
2193 portfwd_handler, P(pfd));
2194 pfd->addbutton->generic.column = 2;
2195 pfd->addbutton->generic.tabdelay = 1;
2196 pfd->sourcebox = ctrl_editbox(s, "Source port", 's', 40,
2197 HELPCTX(ssh_tunnels_portfwd),
2198 portfwd_handler, P(pfd), P(NULL));
2199 pfd->sourcebox->generic.column = 0;
2200 pfd->destbox = ctrl_editbox(s, "Destination", 'i', 67,
2201 HELPCTX(ssh_tunnels_portfwd),
2202 portfwd_handler, P(pfd), P(NULL));
820ebe3b 2203 pfd->direction = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
fe8abbf4 2204 HELPCTX(ssh_tunnels_portfwd),
2205 portfwd_handler, P(pfd),
2206 "Local", 'l', P(NULL),
820ebe3b 2207 "Remote", 'm', P(NULL),
2208 "Dynamic", 'y', P(NULL),
2209 NULL);
05581745 2210#ifndef NO_IPV6
22db244f 2211 pfd->addressfamily =
2212 ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
05581745 2213 HELPCTX(ssh_tunnels_portfwd_ipversion),
2214 portfwd_handler, P(pfd),
b908db15 2215 "Auto", 'u', I(ADDRTYPE_UNSPEC),
2216 "IPv4", '4', I(ADDRTYPE_IPV4),
2217 "IPv6", '6', I(ADDRTYPE_IPV6),
05581745 2218 NULL);
22db244f 2219#endif
fe8abbf4 2220 ctrl_tabdelay(s, pfd->addbutton);
2221 ctrl_columns(s, 1, 100);
2222
fda2feb1 2223 if (!midsession) {
2224 /*
2225 * The Connection/SSH/Bugs panel.
2226 */
2227 ctrl_settitle(b, "Connection/SSH/Bugs",
2228 "Workarounds for SSH server bugs");
2229
2230 s = ctrl_getset(b, "Connection/SSH/Bugs", "main",
2231 "Detection of known bugs in SSH servers");
2e85c969 2232 ctrl_droplist(s, "Chokes on SSH-1 ignore messages", 'i', 20,
fda2feb1 2233 HELPCTX(ssh_bugs_ignore1),
2234 sshbug_handler, I(offsetof(Config,sshbug_ignore1)));
2e85c969 2235 ctrl_droplist(s, "Refuses all SSH-1 password camouflage", 's', 20,
fda2feb1 2236 HELPCTX(ssh_bugs_plainpw1),
2237 sshbug_handler, I(offsetof(Config,sshbug_plainpw1)));
2e85c969 2238 ctrl_droplist(s, "Chokes on SSH-1 RSA authentication", 'r', 20,
fda2feb1 2239 HELPCTX(ssh_bugs_rsa1),
2240 sshbug_handler, I(offsetof(Config,sshbug_rsa1)));
2e85c969 2241 ctrl_droplist(s, "Miscomputes SSH-2 HMAC keys", 'm', 20,
fda2feb1 2242 HELPCTX(ssh_bugs_hmac2),
2243 sshbug_handler, I(offsetof(Config,sshbug_hmac2)));
2e85c969 2244 ctrl_droplist(s, "Miscomputes SSH-2 encryption keys", 'e', 20,
fda2feb1 2245 HELPCTX(ssh_bugs_derivekey2),
2246 sshbug_handler, I(offsetof(Config,sshbug_derivekey2)));
2e85c969 2247 ctrl_droplist(s, "Requires padding on SSH-2 RSA signatures", 'p', 20,
fda2feb1 2248 HELPCTX(ssh_bugs_rsapad2),
2249 sshbug_handler, I(offsetof(Config,sshbug_rsapad2)));
19f47a7d 2250 ctrl_droplist(s, "Misuses the session ID in SSH-2 PK auth", 'n', 20,
fda2feb1 2251 HELPCTX(ssh_bugs_pksessid2),
2252 sshbug_handler, I(offsetof(Config,sshbug_pksessid2)));
19f47a7d 2253 ctrl_droplist(s, "Handles SSH-2 key re-exchange badly", 'k', 20,
f382c87d 2254 HELPCTX(ssh_bugs_rekey2),
2255 sshbug_handler, I(offsetof(Config,sshbug_rekey2)));
c9739dba 2256 ctrl_droplist(s, "Ignores SSH-2 maximum packet size", 'x', 20,
2257 HELPCTX(ssh_bugs_maxpkt2),
2258 sshbug_handler, I(offsetof(Config,sshbug_maxpkt2)));
fda2feb1 2259 }
fe8abbf4 2260 }
2261}