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