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