Consistent indenting in option specs
[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 },
2e85c969 95 { "AES (SSH-2 only)", CIPHER_AES },
fe8abbf4 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 */
04c52f10 405 cfg->remote_cmd_ptr = NULL;
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;
89adc0e2 669#ifndef NO_IPV6
05581745 670 union control *addressfamily;
89adc0e2 671#endif
fe8abbf4 672};
673
674static void portfwd_handler(union control *ctrl, void *dlg,
675 void *data, int event)
676{
677 Config *cfg = (Config *)data;
678 struct portfwd_data *pfd =
679 (struct portfwd_data *)ctrl->generic.context.p;
680
681 if (event == EVENT_REFRESH) {
682 if (ctrl == pfd->listbox) {
683 char *p = cfg->portfwd;
684 dlg_update_start(ctrl, dlg);
685 dlg_listbox_clear(ctrl, dlg);
686 while (*p) {
687 dlg_listbox_add(ctrl, dlg, p);
688 p += strlen(p) + 1;
689 }
690 dlg_update_done(ctrl, dlg);
07e4d76d 691 } else if (ctrl == pfd->direction) {
692 /*
693 * Default is Local.
694 */
695 dlg_radiobutton_set(ctrl, dlg, 0);
89adc0e2 696#ifndef NO_IPV6
697 } else if (ctrl == pfd->addressfamily) {
05581745 698 dlg_radiobutton_set(ctrl, dlg, 0);
89adc0e2 699#endif
fe8abbf4 700 }
701 } else if (event == EVENT_ACTION) {
702 if (ctrl == pfd->addbutton) {
703 char str[sizeof(cfg->portfwd)];
704 char *p;
05581745 705 int i, type;
706 int whichbutton;
707
708 i = 0;
89adc0e2 709#ifndef NO_IPV6
05581745 710 whichbutton = dlg_radiobutton_get(pfd->addressfamily, dlg);
711 if (whichbutton == 1)
712 str[i++] = '4';
713 else if (whichbutton == 2)
714 str[i++] = '6';
89adc0e2 715#endif
05581745 716
717 whichbutton = dlg_radiobutton_get(pfd->direction, dlg);
820ebe3b 718 if (whichbutton == 0)
05581745 719 type = 'L';
820ebe3b 720 else if (whichbutton == 1)
05581745 721 type = 'R';
820ebe3b 722 else
05581745 723 type = 'D';
724 str[i++] = type;
725
726 dlg_editbox_get(pfd->sourcebox, dlg, str+i, sizeof(str) - i);
94042edc 727 if (!str[i]) {
fe8abbf4 728 dlg_error_msg(dlg, "You need to specify a source port number");
729 return;
730 }
731 p = str + strlen(str);
05581745 732 if (type != 'D') {
820ebe3b 733 *p++ = '\t';
734 dlg_editbox_get(pfd->destbox, dlg, p,
e49c58ed 735 sizeof(str) - (p - str));
820ebe3b 736 if (!*p || !strchr(p, ':')) {
737 dlg_error_msg(dlg,
738 "You need to specify a destination address\n"
739 "in the form \"host.name:port\"");
740 return;
741 }
742 } else
743 *p = '\0';
fe8abbf4 744 p = cfg->portfwd;
745 while (*p) {
746 while (*p)
747 p++;
748 p++;
749 }
e49c58ed 750 if ((p - cfg->portfwd) + strlen(str) + 2 <=
fe8abbf4 751 sizeof(cfg->portfwd)) {
752 strcpy(p, str);
753 p[strlen(str) + 1] = '\0';
754 dlg_listbox_add(pfd->listbox, dlg, str);
755 dlg_editbox_set(pfd->sourcebox, dlg, "");
756 dlg_editbox_set(pfd->destbox, dlg, "");
757 } else {
758 dlg_error_msg(dlg, "Too many forwardings");
759 }
760 } else if (ctrl == pfd->rembutton) {
761 int i = dlg_listbox_index(pfd->listbox, dlg);
762 if (i < 0)
763 dlg_beep(dlg);
764 else {
765 char *p, *q;
766
767 dlg_listbox_del(pfd->listbox, dlg, i);
768 p = cfg->portfwd;
769 while (i > 0) {
770 if (!*p)
771 goto disaster2;
772 while (*p)
773 p++;
774 p++;
775 i--;
776 }
777 q = p;
778 if (!*p)
779 goto disaster2;
780 while (*p)
781 p++;
782 p++;
783 while (*p) {
784 while (*p)
785 *q++ = *p++;
786 *q++ = *p++;
787 }
788 *q = '\0';
789 disaster2:;
790 }
791 }
792 }
793}
794
795void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
f89c3294 796 int midsession, int protocol, int protcfginfo)
fe8abbf4 797{
798 struct controlset *s;
799 struct sessionsaver_data *ssd;
800 struct charclass_data *ccd;
801 struct colour_data *cd;
802 struct environ_data *ed;
803 struct portfwd_data *pfd;
804 union control *c;
f6f450e2 805 char *str;
fe8abbf4 806
807 ssd = (struct sessionsaver_data *)
808 ctrl_alloc(b, sizeof(struct sessionsaver_data));
56b9b9a7 809 memset(ssd, 0, sizeof(*ssd));
2e155f47 810 ssd->midsession = midsession;
fe8abbf4 811
812 /*
813 * The standard panel that appears at the bottom of all panels:
814 * Open, Cancel, Apply etc.
815 */
816 s = ctrl_getset(b, "", "", "");
817 ctrl_columns(s, 5, 20, 20, 20, 20, 20);
818 ssd->okbutton = ctrl_pushbutton(s,
819 (midsession ? "Apply" : "Open"),
820 (char)(midsession ? 'a' : 'o'),
821 HELPCTX(no_help),
822 sessionsaver_handler, P(ssd));
823 ssd->okbutton->button.isdefault = TRUE;
824 ssd->okbutton->generic.column = 3;
825 ssd->cancelbutton = ctrl_pushbutton(s, "Cancel", 'c', HELPCTX(no_help),
826 sessionsaver_handler, P(ssd));
0bd8d76d 827 ssd->cancelbutton->button.iscancel = TRUE;
fe8abbf4 828 ssd->cancelbutton->generic.column = 4;
829 /* We carefully don't close the 5-column part, so that platform-
830 * specific add-ons can put extra buttons alongside Open and Cancel. */
831
832 /*
833 * The Session panel.
834 */
f6f450e2 835 str = dupprintf("Basic options for your %s session", appname);
836 ctrl_settitle(b, "Session", str);
837 sfree(str);
fe8abbf4 838
839 if (!midsession) {
840 s = ctrl_getset(b, "Session", "hostport",
841 "Specify your connection by host name or IP address");
842 ctrl_columns(s, 2, 75, 25);
843 c = ctrl_editbox(s, "Host Name (or IP address)", 'n', 100,
844 HELPCTX(session_hostname),
845 dlg_stdeditbox_handler, I(offsetof(Config,host)),
846 I(sizeof(((Config *)0)->host)));
847 c->generic.column = 0;
848 c = ctrl_editbox(s, "Port", 'p', 100, HELPCTX(session_hostname),
849 dlg_stdeditbox_handler,
850 I(offsetof(Config,port)), I(-1));
851 c->generic.column = 1;
852 ctrl_columns(s, 1, 100);
d9b15094 853 if (backends[3].name == NULL) {
fe8abbf4 854 ctrl_radiobuttons(s, "Protocol:", NO_SHORTCUT, 3,
855 HELPCTX(session_hostname),
856 protocolbuttons_handler, P(c),
857 "Raw", 'r', I(PROT_RAW),
858 "Telnet", 't', I(PROT_TELNET),
859 "Rlogin", 'i', I(PROT_RLOGIN),
860 NULL);
861 } else {
862 ctrl_radiobuttons(s, "Protocol:", NO_SHORTCUT, 4,
863 HELPCTX(session_hostname),
864 protocolbuttons_handler, P(c),
865 "Raw", 'r', I(PROT_RAW),
866 "Telnet", 't', I(PROT_TELNET),
867 "Rlogin", 'i', I(PROT_RLOGIN),
868 "SSH", 's', I(PROT_SSH),
869 NULL);
870 }
fe8abbf4 871 }
872
48c4dd7c 873 /*
874 * The Load/Save panel is available even in mid-session.
875 */
876 s = ctrl_getset(b, "Session", "savedsessions",
59b8cd5a 877 midsession ? "Save the current session settings" :
48c4dd7c 878 "Load, save or delete a stored session");
879 ctrl_columns(s, 2, 75, 25);
880 ssd->sesslist = sesslist;
881 ssd->editbox = ctrl_editbox(s, "Saved Sessions", 'e', 100,
882 HELPCTX(session_saved),
883 sessionsaver_handler, P(ssd), P(NULL));
884 ssd->editbox->generic.column = 0;
885 /* Reset columns so that the buttons are alongside the list, rather
886 * than alongside that edit box. */
887 ctrl_columns(s, 1, 100);
888 ctrl_columns(s, 2, 75, 25);
889 ssd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
890 HELPCTX(session_saved),
891 sessionsaver_handler, P(ssd));
892 ssd->listbox->generic.column = 0;
893 ssd->listbox->listbox.height = 7;
2e155f47 894 if (!midsession) {
895 ssd->loadbutton = ctrl_pushbutton(s, "Load", 'l',
896 HELPCTX(session_saved),
897 sessionsaver_handler, P(ssd));
898 ssd->loadbutton->generic.column = 1;
899 } else {
900 /* We can't offer the Load button mid-session, as it would allow the
901 * user to load and subsequently save settings they can't see. (And
902 * also change otherwise immutable settings underfoot; that probably
903 * shouldn't be a problem, but.) */
904 ssd->loadbutton = NULL;
905 }
906 /* "Save" button is permitted mid-session. */
48c4dd7c 907 ssd->savebutton = ctrl_pushbutton(s, "Save", 'v',
908 HELPCTX(session_saved),
909 sessionsaver_handler, P(ssd));
910 ssd->savebutton->generic.column = 1;
2e155f47 911 if (!midsession) {
912 ssd->delbutton = ctrl_pushbutton(s, "Delete", 'd',
913 HELPCTX(session_saved),
914 sessionsaver_handler, P(ssd));
915 ssd->delbutton->generic.column = 1;
916 } else {
917 /* Disable the Delete button mid-session too, for UI consistency. */
918 ssd->delbutton = NULL;
919 }
48c4dd7c 920 ctrl_columns(s, 1, 100);
921
fe8abbf4 922 s = ctrl_getset(b, "Session", "otheropts", NULL);
923 c = ctrl_radiobuttons(s, "Close window on exit:", 'w', 4,
924 HELPCTX(session_coe),
925 dlg_stdradiobutton_handler,
926 I(offsetof(Config, close_on_exit)),
927 "Always", I(FORCE_ON),
928 "Never", I(FORCE_OFF),
929 "Only on clean exit", I(AUTO), NULL);
930
931 /*
932 * The Session/Logging panel.
933 */
934 ctrl_settitle(b, "Session/Logging", "Options controlling session logging");
935
936 s = ctrl_getset(b, "Session/Logging", "main", NULL);
3e547dd8 937 /*
938 * The logging buttons change depending on whether SSH packet
939 * logging can sensibly be available.
940 */
941 {
942 char *sshlogname;
943 if ((midsession && protocol == PROT_SSH) ||
944 (!midsession && backends[3].name != NULL))
945 sshlogname = "Log SSH packet data";
946 else
947 sshlogname = NULL; /* this will disable the button */
948 ctrl_radiobuttons(s, "Session logging:", NO_SHORTCUT, 1,
949 HELPCTX(logging_main),
950 dlg_stdradiobutton_handler,
951 I(offsetof(Config, logtype)),
952 "Logging turned off completely", 't', I(LGTYP_NONE),
953 "Log printable output only", 'p', I(LGTYP_ASCII),
954 "Log all session output", 'l', I(LGTYP_DEBUG),
955 sshlogname, 's', I(LGTYP_PACKETS),
956 NULL);
957 }
fe8abbf4 958 ctrl_filesel(s, "Log file name:", 'f',
959 NULL, TRUE, "Select session log file name",
960 HELPCTX(logging_filename),
961 dlg_stdfilesel_handler, I(offsetof(Config, logfilename)));
962 ctrl_text(s, "(Log file name can contain &Y, &M, &D for date,"
963 " &T for time, and &H for host name)",
964 HELPCTX(logging_filename));
965 ctrl_radiobuttons(s, "What to do if the log file already exists:", 'e', 1,
966 HELPCTX(logging_exists),
967 dlg_stdradiobutton_handler, I(offsetof(Config,logxfovr)),
968 "Always overwrite it", I(LGXF_OVR),
969 "Always append to the end of it", I(LGXF_APN),
970 "Ask the user every time", I(LGXF_ASK), NULL);
6d60c791 971 ctrl_checkbox(s, "Flush log file frequently", 'u',
972 HELPCTX(logging_flush),
973 dlg_stdcheckbox_handler, I(offsetof(Config,logflush)));
fe8abbf4 974
9a10ecf4 975 if ((midsession && protocol == PROT_SSH) ||
976 (!midsession && backends[3].name != NULL)) {
977 s = ctrl_getset(b, "Session/Logging", "ssh",
978 "Options specific to SSH packet logging");
979 ctrl_checkbox(s, "Omit known password fields", 'k',
980 HELPCTX(logging_ssh_omit_password),
981 dlg_stdcheckbox_handler, I(offsetof(Config,logomitpass)));
982 ctrl_checkbox(s, "Omit session data", 'd',
983 HELPCTX(logging_ssh_omit_data),
984 dlg_stdcheckbox_handler, I(offsetof(Config,logomitdata)));
985 }
986
fe8abbf4 987 /*
988 * The Terminal panel.
989 */
990 ctrl_settitle(b, "Terminal", "Options controlling the terminal emulation");
991
992 s = ctrl_getset(b, "Terminal", "general", "Set various terminal options");
993 ctrl_checkbox(s, "Auto wrap mode initially on", 'w',
994 HELPCTX(terminal_autowrap),
995 dlg_stdcheckbox_handler, I(offsetof(Config,wrap_mode)));
996 ctrl_checkbox(s, "DEC Origin Mode initially on", 'd',
997 HELPCTX(terminal_decom),
998 dlg_stdcheckbox_handler, I(offsetof(Config,dec_om)));
999 ctrl_checkbox(s, "Implicit CR in every LF", 'r',
1000 HELPCTX(terminal_lfhascr),
1001 dlg_stdcheckbox_handler, I(offsetof(Config,lfhascr)));
1002 ctrl_checkbox(s, "Use background colour to erase screen", 'e',
1003 HELPCTX(terminal_bce),
1004 dlg_stdcheckbox_handler, I(offsetof(Config,bce)));
1005 ctrl_checkbox(s, "Enable blinking text", 'n',
1006 HELPCTX(terminal_blink),
1007 dlg_stdcheckbox_handler, I(offsetof(Config,blinktext)));
1008 ctrl_editbox(s, "Answerback to ^E:", 's', 100,
1009 HELPCTX(terminal_answerback),
1010 dlg_stdeditbox_handler, I(offsetof(Config,answerback)),
1011 I(sizeof(((Config *)0)->answerback)));
1012
1013 s = ctrl_getset(b, "Terminal", "ldisc", "Line discipline options");
1014 ctrl_radiobuttons(s, "Local echo:", 'l', 3,
1015 HELPCTX(terminal_localecho),
1016 dlg_stdradiobutton_handler,I(offsetof(Config,localecho)),
1017 "Auto", I(AUTO),
1018 "Force on", I(FORCE_ON),
1019 "Force off", I(FORCE_OFF), NULL);
1020 ctrl_radiobuttons(s, "Local line editing:", 't', 3,
1021 HELPCTX(terminal_localedit),
1022 dlg_stdradiobutton_handler,I(offsetof(Config,localedit)),
1023 "Auto", I(AUTO),
1024 "Force on", I(FORCE_ON),
1025 "Force off", I(FORCE_OFF), NULL);
1026
1027 s = ctrl_getset(b, "Terminal", "printing", "Remote-controlled printing");
1028 ctrl_combobox(s, "Printer to send ANSI printer output to:", 'p', 100,
1029 HELPCTX(terminal_printing),
1030 printerbox_handler, P(NULL), P(NULL));
1031
1032 /*
1033 * The Terminal/Keyboard panel.
1034 */
1035 ctrl_settitle(b, "Terminal/Keyboard",
1036 "Options controlling the effects of keys");
1037
1038 s = ctrl_getset(b, "Terminal/Keyboard", "mappings",
1039 "Change the sequences sent by:");
1040 ctrl_radiobuttons(s, "The Backspace key", 'b', 2,
1041 HELPCTX(keyboard_backspace),
1042 dlg_stdradiobutton_handler,
1043 I(offsetof(Config, bksp_is_delete)),
1044 "Control-H", I(0), "Control-? (127)", I(1), NULL);
1045 ctrl_radiobuttons(s, "The Home and End keys", 'e', 2,
1046 HELPCTX(keyboard_homeend),
1047 dlg_stdradiobutton_handler,
1048 I(offsetof(Config, rxvt_homeend)),
1049 "Standard", I(0), "rxvt", I(1), NULL);
1050 ctrl_radiobuttons(s, "The Function keys and keypad", 'f', 3,
1051 HELPCTX(keyboard_funkeys),
1052 dlg_stdradiobutton_handler,
1053 I(offsetof(Config, funky_type)),
1054 "ESC[n~", I(0), "Linux", I(1), "Xterm R6", I(2),
1055 "VT400", I(3), "VT100+", I(4), "SCO", I(5), NULL);
1056
1057 s = ctrl_getset(b, "Terminal/Keyboard", "appkeypad",
1058 "Application keypad settings:");
1059 ctrl_radiobuttons(s, "Initial state of cursor keys:", 'r', 3,
1060 HELPCTX(keyboard_appcursor),
1061 dlg_stdradiobutton_handler,
1062 I(offsetof(Config, app_cursor)),
1063 "Normal", I(0), "Application", I(1), NULL);
1064 ctrl_radiobuttons(s, "Initial state of numeric keypad:", 'n', 3,
1065 HELPCTX(keyboard_appkeypad),
1066 numeric_keypad_handler, P(NULL),
1067 "Normal", I(0), "Application", I(1), "NetHack", I(2),
1068 NULL);
1069
1070 /*
1071 * The Terminal/Bell panel.
1072 */
1073 ctrl_settitle(b, "Terminal/Bell",
1074 "Options controlling the terminal bell");
1075
1076 s = ctrl_getset(b, "Terminal/Bell", "style", "Set the style of bell");
1077 ctrl_radiobuttons(s, "Action to happen when a bell occurs:", 'b', 1,
1078 HELPCTX(bell_style),
1079 dlg_stdradiobutton_handler, I(offsetof(Config, beep)),
1080 "None (bell disabled)", I(BELL_DISABLED),
1081 "Make default system alert sound", I(BELL_DEFAULT),
1082 "Visual bell (flash window)", I(BELL_VISUAL), NULL);
1083
1084 s = ctrl_getset(b, "Terminal/Bell", "overload",
1085 "Control the bell overload behaviour");
1086 ctrl_checkbox(s, "Bell is temporarily disabled when over-used", 'd',
1087 HELPCTX(bell_overload),
1088 dlg_stdcheckbox_handler, I(offsetof(Config,bellovl)));
1089 ctrl_editbox(s, "Over-use means this many bells...", 'm', 20,
1090 HELPCTX(bell_overload),
1091 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_n)), I(-1));
1092 ctrl_editbox(s, "... in this many seconds", 't', 20,
1093 HELPCTX(bell_overload),
1094 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_t)),
62697e04 1095 I(-TICKSPERSEC));
fe8abbf4 1096 ctrl_text(s, "The bell is re-enabled after a few seconds of silence.",
1097 HELPCTX(bell_overload));
1098 ctrl_editbox(s, "Seconds of silence required", 's', 20,
1099 HELPCTX(bell_overload),
1100 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_s)),
62697e04 1101 I(-TICKSPERSEC));
fe8abbf4 1102
1103 /*
1104 * The Terminal/Features panel.
1105 */
1106 ctrl_settitle(b, "Terminal/Features",
1107 "Enabling and disabling advanced terminal features");
1108
1109 s = ctrl_getset(b, "Terminal/Features", "main", NULL);
1110 ctrl_checkbox(s, "Disable application cursor keys mode", 'u',
1111 HELPCTX(features_application),
1112 dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_c)));
1113 ctrl_checkbox(s, "Disable application keypad mode", 'k',
1114 HELPCTX(features_application),
1115 dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_k)));
1116 ctrl_checkbox(s, "Disable xterm-style mouse reporting", 'x',
1117 HELPCTX(features_mouse),
1118 dlg_stdcheckbox_handler, I(offsetof(Config,no_mouse_rep)));
1119 ctrl_checkbox(s, "Disable remote-controlled terminal resizing", 's',
1120 HELPCTX(features_resize),
1121 dlg_stdcheckbox_handler,
1122 I(offsetof(Config,no_remote_resize)));
1123 ctrl_checkbox(s, "Disable switching to alternate terminal screen", 'w',
1124 HELPCTX(features_altscreen),
1125 dlg_stdcheckbox_handler, I(offsetof(Config,no_alt_screen)));
1126 ctrl_checkbox(s, "Disable remote-controlled window title changing", 't',
1127 HELPCTX(features_retitle),
1128 dlg_stdcheckbox_handler,
1129 I(offsetof(Config,no_remote_wintitle)));
7fcdebd3 1130 ctrl_checkbox(s, "Disable remote window title querying (SECURITY)",
1131 'q', HELPCTX(features_qtitle), dlg_stdcheckbox_handler,
1132 I(offsetof(Config,no_remote_qtitle)));
fe8abbf4 1133 ctrl_checkbox(s, "Disable destructive backspace on server sending ^?",'b',
1134 HELPCTX(features_dbackspace),
1135 dlg_stdcheckbox_handler, I(offsetof(Config,no_dbackspace)));
1136 ctrl_checkbox(s, "Disable remote-controlled character set configuration",
1137 'r', HELPCTX(features_charset), dlg_stdcheckbox_handler,
1138 I(offsetof(Config,no_remote_charset)));
f0fccd51 1139 ctrl_checkbox(s, "Disable Arabic text shaping",
f4ec0818 1140 'l', HELPCTX(features_arabicshaping), dlg_stdcheckbox_handler,
f0fccd51 1141 I(offsetof(Config, arabicshaping)));
1142 ctrl_checkbox(s, "Disable bidirectional text display",
f4ec0818 1143 'd', HELPCTX(features_bidi), dlg_stdcheckbox_handler,
f0fccd51 1144 I(offsetof(Config, bidi)));
fe8abbf4 1145
1146 /*
1147 * The Window panel.
1148 */
f6f450e2 1149 str = dupprintf("Options controlling %s's window", appname);
1150 ctrl_settitle(b, "Window", str);
1151 sfree(str);
fe8abbf4 1152
1153 s = ctrl_getset(b, "Window", "size", "Set the size of the window");
1154 ctrl_columns(s, 2, 50, 50);
1155 c = ctrl_editbox(s, "Rows", 'r', 100,
1156 HELPCTX(window_size),
1157 dlg_stdeditbox_handler, I(offsetof(Config,height)),I(-1));
1158 c->generic.column = 0;
1159 c = ctrl_editbox(s, "Columns", 'm', 100,
1160 HELPCTX(window_size),
1161 dlg_stdeditbox_handler, I(offsetof(Config,width)), I(-1));
1162 c->generic.column = 1;
1163 ctrl_columns(s, 1, 100);
1164
1165 s = ctrl_getset(b, "Window", "scrollback",
1166 "Control the scrollback in the window");
1167 ctrl_editbox(s, "Lines of scrollback", 's', 50,
1168 HELPCTX(window_scrollback),
1169 dlg_stdeditbox_handler, I(offsetof(Config,savelines)), I(-1));
1170 ctrl_checkbox(s, "Display scrollbar", 'd',
1171 HELPCTX(window_scrollback),
1172 dlg_stdcheckbox_handler, I(offsetof(Config,scrollbar)));
fe8abbf4 1173 ctrl_checkbox(s, "Reset scrollback on keypress", 'k',
1174 HELPCTX(window_scrollback),
1175 dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_key)));
1176 ctrl_checkbox(s, "Reset scrollback on display activity", 'p',
1177 HELPCTX(window_scrollback),
1178 dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_disp)));
876e5d5e 1179 ctrl_checkbox(s, "Push erased text into scrollback", 'e',
1180 HELPCTX(window_erased),
1181 dlg_stdcheckbox_handler,
1182 I(offsetof(Config,erase_to_scrollback)));
fe8abbf4 1183
1184 /*
1185 * The Window/Appearance panel.
1186 */
f6f450e2 1187 str = dupprintf("Configure the appearance of %s's window", appname);
1188 ctrl_settitle(b, "Window/Appearance", str);
1189 sfree(str);
fe8abbf4 1190
1191 s = ctrl_getset(b, "Window/Appearance", "cursor",
1192 "Adjust the use of the cursor");
1193 ctrl_radiobuttons(s, "Cursor appearance:", NO_SHORTCUT, 3,
1194 HELPCTX(appearance_cursor),
1195 dlg_stdradiobutton_handler,
1196 I(offsetof(Config, cursor_type)),
1197 "Block", 'l', I(0),
1198 "Underline", 'u', I(1),
1199 "Vertical line", 'v', I(2), NULL);
1200 ctrl_checkbox(s, "Cursor blinks", 'b',
1201 HELPCTX(appearance_cursor),
1202 dlg_stdcheckbox_handler, I(offsetof(Config,blink_cur)));
1203
1204 s = ctrl_getset(b, "Window/Appearance", "font",
1205 "Font settings");
1206 ctrl_fontsel(s, "Font used in the terminal window", 'n',
1207 HELPCTX(appearance_font),
1208 dlg_stdfontsel_handler, I(offsetof(Config, font)));
1209
1210 s = ctrl_getset(b, "Window/Appearance", "mouse",
1211 "Adjust the use of the mouse pointer");
1212 ctrl_checkbox(s, "Hide mouse pointer when typing in window", 'p',
1213 HELPCTX(appearance_hidemouse),
1214 dlg_stdcheckbox_handler, I(offsetof(Config,hide_mouseptr)));
1215
1216 s = ctrl_getset(b, "Window/Appearance", "border",
1217 "Adjust the window border");
1218 ctrl_editbox(s, "Gap between text and window edge:", NO_SHORTCUT, 20,
1219 HELPCTX(appearance_border),
1220 dlg_stdeditbox_handler,
1221 I(offsetof(Config,window_border)), I(-1));
1222
1223 /*
1224 * The Window/Behaviour panel.
1225 */
f6f450e2 1226 str = dupprintf("Configure the behaviour of %s's window", appname);
1227 ctrl_settitle(b, "Window/Behaviour", str);
1228 sfree(str);
fe8abbf4 1229
1230 s = ctrl_getset(b, "Window/Behaviour", "title",
1231 "Adjust the behaviour of the window title");
1232 ctrl_editbox(s, "Window title:", 't', 100,
1233 HELPCTX(appearance_title),
1234 dlg_stdeditbox_handler, I(offsetof(Config,wintitle)),
1235 I(sizeof(((Config *)0)->wintitle)));
1236 ctrl_checkbox(s, "Separate window and icon titles", 'i',
1237 HELPCTX(appearance_title),
1238 dlg_stdcheckbox_handler,
1239 I(CHECKBOX_INVERT | offsetof(Config,win_name_always)));
1240
1241 s = ctrl_getset(b, "Window/Behaviour", "main", NULL);
1242 ctrl_checkbox(s, "Warn before closing window", 'w',
1243 HELPCTX(behaviour_closewarn),
1244 dlg_stdcheckbox_handler, I(offsetof(Config,warn_on_close)));
1245
1246 /*
1247 * The Window/Translation panel.
1248 */
1249 ctrl_settitle(b, "Window/Translation",
1250 "Options controlling character set translation");
1251
1252 s = ctrl_getset(b, "Window/Translation", "trans",
1253 "Character set translation on received data");
1254 ctrl_combobox(s, "Received data assumed to be in which character set:",
1255 'r', 100, HELPCTX(translation_codepage),
1256 codepage_handler, P(NULL), P(NULL));
1257
00381fc7 1258 str = dupprintf("Adjust how %s handles line drawing characters", appname);
f6f450e2 1259 s = ctrl_getset(b, "Window/Translation", "linedraw", str);
1260 sfree(str);
fe8abbf4 1261 ctrl_radiobuttons(s, "Handling of line drawing characters:", NO_SHORTCUT,1,
1262 HELPCTX(translation_linedraw),
1263 dlg_stdradiobutton_handler,
1264 I(offsetof(Config, vtmode)),
3900c2d6 1265 "Use Unicode line drawing code points",'u',I(VT_UNICODE),
fe8abbf4 1266 "Poor man's line drawing (+, - and |)",'p',I(VT_POORMAN),
3900c2d6 1267 NULL);
00381fc7 1268 ctrl_checkbox(s, "Copy and paste line drawing characters as lqqqk",'d',
1269 HELPCTX(selection_linedraw),
1270 dlg_stdcheckbox_handler, I(offsetof(Config,rawcnp)));
fe8abbf4 1271
1272 /*
1273 * The Window/Selection panel.
1274 */
1275 ctrl_settitle(b, "Window/Selection", "Options controlling copy and paste");
fe8abbf4 1276
1277 s = ctrl_getset(b, "Window/Selection", "mouse",
1278 "Control use of mouse");
1279 ctrl_checkbox(s, "Shift overrides application's use of mouse", 'p',
1280 HELPCTX(selection_shiftdrag),
1281 dlg_stdcheckbox_handler, I(offsetof(Config,mouse_override)));
1282 ctrl_radiobuttons(s,
1283 "Default selection mode (Alt+drag does the other one):",
1284 NO_SHORTCUT, 2,
1285 HELPCTX(selection_rect),
1286 dlg_stdradiobutton_handler,
1287 I(offsetof(Config, rect_select)),
1288 "Normal", 'n', I(0),
1289 "Rectangular block", 'r', I(1), NULL);
1290
1291 s = ctrl_getset(b, "Window/Selection", "charclass",
1292 "Control the select-one-word-at-a-time mode");
1293 ccd = (struct charclass_data *)
1294 ctrl_alloc(b, sizeof(struct charclass_data));
1295 ccd->listbox = ctrl_listbox(s, "Character classes:", 'e',
1296 HELPCTX(selection_charclasses),
1297 charclass_handler, P(ccd));
1298 ccd->listbox->listbox.multisel = 1;
1299 ccd->listbox->listbox.ncols = 4;
3d88e64d 1300 ccd->listbox->listbox.percentages = snewn(4, int);
fe8abbf4 1301 ccd->listbox->listbox.percentages[0] = 15;
1302 ccd->listbox->listbox.percentages[1] = 25;
1303 ccd->listbox->listbox.percentages[2] = 20;
1304 ccd->listbox->listbox.percentages[3] = 40;
1305 ctrl_columns(s, 2, 67, 33);
1306 ccd->editbox = ctrl_editbox(s, "Set to class", 't', 50,
1307 HELPCTX(selection_charclasses),
1308 charclass_handler, P(ccd), P(NULL));
1309 ccd->editbox->generic.column = 0;
1310 ccd->button = ctrl_pushbutton(s, "Set", 's',
1311 HELPCTX(selection_charclasses),
1312 charclass_handler, P(ccd));
1313 ccd->button->generic.column = 1;
1314 ctrl_columns(s, 1, 100);
1315
1316 /*
1317 * The Window/Colours panel.
1318 */
1319 ctrl_settitle(b, "Window/Colours", "Options controlling use of colours");
1320
1321 s = ctrl_getset(b, "Window/Colours", "general",
1322 "General options for colour usage");
c6f1b8ed 1323 ctrl_checkbox(s, "Allow terminal to specify ANSI colours", 'i',
1324 HELPCTX(colours_ansi),
1325 dlg_stdcheckbox_handler, I(offsetof(Config,ansi_colour)));
cecb13f6 1326 ctrl_checkbox(s, "Allow terminal to use xterm 256-colour mode", '2',
1327 HELPCTX(colours_xterm256), dlg_stdcheckbox_handler,
1328 I(offsetof(Config,xterm_256_colour)));
fe8abbf4 1329 ctrl_checkbox(s, "Bolded text is a different colour", 'b',
1330 HELPCTX(colours_bold),
1331 dlg_stdcheckbox_handler, I(offsetof(Config,bold_colour)));
1332
f6f450e2 1333 str = dupprintf("Adjust the precise colours %s displays", appname);
1334 s = ctrl_getset(b, "Window/Colours", "adjust", str);
1335 sfree(str);
fe8abbf4 1336 ctrl_text(s, "Select a colour from the list, and then click the"
1337 " Modify button to change its appearance.",
1338 HELPCTX(colours_config));
1339 ctrl_columns(s, 2, 67, 33);
1340 cd = (struct colour_data *)ctrl_alloc(b, sizeof(struct colour_data));
1341 cd->listbox = ctrl_listbox(s, "Select a colour to adjust:", 'u',
1342 HELPCTX(colours_config), colour_handler, P(cd));
1343 cd->listbox->generic.column = 0;
18c2f87c 1344 cd->listbox->listbox.height = 7;
fe8abbf4 1345 c = ctrl_text(s, "RGB value:", HELPCTX(colours_config));
1346 c->generic.column = 1;
18c2f87c 1347 cd->redit = ctrl_editbox(s, "Red", 'r', 50, HELPCTX(colours_config),
1348 colour_handler, P(cd), P(NULL));
1349 cd->redit->generic.column = 1;
1350 cd->gedit = ctrl_editbox(s, "Green", 'n', 50, HELPCTX(colours_config),
1351 colour_handler, P(cd), P(NULL));
1352 cd->gedit->generic.column = 1;
1353 cd->bedit = ctrl_editbox(s, "Blue", 'e', 50, HELPCTX(colours_config),
1354 colour_handler, P(cd), P(NULL));
1355 cd->bedit->generic.column = 1;
fe8abbf4 1356 cd->button = ctrl_pushbutton(s, "Modify", 'm', HELPCTX(colours_config),
1357 colour_handler, P(cd));
1358 cd->button->generic.column = 1;
1359 ctrl_columns(s, 1, 100);
1360
1361 /*
3e547dd8 1362 * The Connection panel. This doesn't show up if we're in a
1363 * non-network utility such as pterm. We tell this by being
1364 * passed a protocol < 0.
fe8abbf4 1365 */
3e547dd8 1366 if (protocol >= 0) {
1367 ctrl_settitle(b, "Connection", "Options controlling the connection");
1368
05581745 1369 s = ctrl_getset(b, "Connection", "keepalive",
1370 "Sending of null packets to keep session active");
1371 ctrl_editbox(s, "Seconds between keepalives (0 to turn off)", 'k', 20,
1372 HELPCTX(connection_keepalive),
1373 dlg_stdeditbox_handler, I(offsetof(Config,ping_interval)),
1374 I(-1));
1375
3e547dd8 1376 if (!midsession) {
05581745 1377 s = ctrl_getset(b, "Connection", "tcp",
1378 "Low-level TCP connection options");
1379 ctrl_checkbox(s, "Disable Nagle's algorithm (TCP_NODELAY option)",
1380 'n', HELPCTX(connection_nodelay),
1381 dlg_stdcheckbox_handler,
1382 I(offsetof(Config,tcp_nodelay)));
1383 ctrl_checkbox(s, "Enable TCP keepalives (SO_KEEPALIVE option)",
1384 'p', HELPCTX(connection_tcpkeepalive),
1385 dlg_stdcheckbox_handler,
1386 I(offsetof(Config,tcp_keepalives)));
22db244f 1387#ifndef NO_IPV6
05581745 1388 s = ctrl_getset(b, "Connection", "ipversion",
1389 "Internet protocol version");
22db244f 1390 ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
05581745 1391 HELPCTX(connection_ipversion),
1392 dlg_stdradiobutton_handler,
1393 I(offsetof(Config, addressfamily)),
1394 "Auto", NO_SHORTCUT, I(ADDRTYPE_UNSPEC),
1395 "IPv4", NO_SHORTCUT, I(ADDRTYPE_IPV4),
05581745 1396 "IPv6", NO_SHORTCUT, I(ADDRTYPE_IPV6),
05581745 1397 NULL);
22db244f 1398#endif
05581745 1399 }
1400
1401 /*
1402 * A sub-panel Connection/Data, containing options that
1403 * decide on data to send to the server.
1404 */
1405 if (!midsession) {
1406 ctrl_settitle(b, "Connection/Data", "Data to send to the server");
1407
1408 s = ctrl_getset(b, "Connection/Data", "login",
1409 "Login details");
1410 ctrl_editbox(s, "Auto-login username", 'u', 50,
1411 HELPCTX(connection_username),
1412 dlg_stdeditbox_handler, I(offsetof(Config,username)),
1413 I(sizeof(((Config *)0)->username)));
1414
1415 s = ctrl_getset(b, "Connection/Data", "term",
1416 "Terminal details");
3e547dd8 1417 ctrl_editbox(s, "Terminal-type string", 't', 50,
1418 HELPCTX(connection_termtype),
1419 dlg_stdeditbox_handler, I(offsetof(Config,termtype)),
1420 I(sizeof(((Config *)0)->termtype)));
a5dd8467 1421 ctrl_editbox(s, "Terminal speeds", 's', 50,
1422 HELPCTX(connection_termspeed),
1423 dlg_stdeditbox_handler, I(offsetof(Config,termspeed)),
1424 I(sizeof(((Config *)0)->termspeed)));
73feed4f 1425
05581745 1426 s = ctrl_getset(b, "Connection/Data", "env",
1427 "Environment variables");
73feed4f 1428 ctrl_columns(s, 2, 80, 20);
1429 ed = (struct environ_data *)
1430 ctrl_alloc(b, sizeof(struct environ_data));
1431 ed->varbox = ctrl_editbox(s, "Variable", 'v', 60,
1432 HELPCTX(telnet_environ),
1433 environ_handler, P(ed), P(NULL));
1434 ed->varbox->generic.column = 0;
1435 ed->valbox = ctrl_editbox(s, "Value", 'l', 60,
1436 HELPCTX(telnet_environ),
1437 environ_handler, P(ed), P(NULL));
1438 ed->valbox->generic.column = 0;
1439 ed->addbutton = ctrl_pushbutton(s, "Add", 'd',
1440 HELPCTX(telnet_environ),
1441 environ_handler, P(ed));
1442 ed->addbutton->generic.column = 1;
1443 ed->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1444 HELPCTX(telnet_environ),
1445 environ_handler, P(ed));
1446 ed->rembutton->generic.column = 1;
1447 ctrl_columns(s, 1, 100);
1448 ed->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1449 HELPCTX(telnet_environ),
1450 environ_handler, P(ed));
1451 ed->listbox->listbox.height = 3;
1452 ed->listbox->listbox.ncols = 2;
1453 ed->listbox->listbox.percentages = snewn(2, int);
1454 ed->listbox->listbox.percentages[0] = 30;
1455 ed->listbox->listbox.percentages[1] = 70;
3e547dd8 1456 }
fe8abbf4 1457
fe8abbf4 1458 }
1459
1460 if (!midsession) {
1461 /*
1462 * The Connection/Proxy panel.
1463 */
1464 ctrl_settitle(b, "Connection/Proxy",
1465 "Options controlling proxy usage");
1466
10068a0b 1467 s = ctrl_getset(b, "Connection/Proxy", "basics", NULL);
1468 ctrl_radiobuttons(s, "Proxy type:", 't', 3,
fe8abbf4 1469 HELPCTX(proxy_type),
1470 dlg_stdradiobutton_handler,
1471 I(offsetof(Config, proxy_type)),
0f0a2507 1472 "None", I(PROXY_NONE),
10068a0b 1473 "SOCKS 4", I(PROXY_SOCKS4),
1474 "SOCKS 5", I(PROXY_SOCKS5),
0f0a2507 1475 "HTTP", I(PROXY_HTTP),
0f0a2507 1476 "Telnet", I(PROXY_TELNET),
fe8abbf4 1477 NULL);
1478 ctrl_columns(s, 2, 80, 20);
1479 c = ctrl_editbox(s, "Proxy hostname", 'y', 100,
1480 HELPCTX(proxy_main),
1481 dlg_stdeditbox_handler,
1482 I(offsetof(Config,proxy_host)),
1483 I(sizeof(((Config *)0)->proxy_host)));
1484 c->generic.column = 0;
1485 c = ctrl_editbox(s, "Port", 'p', 100,
1486 HELPCTX(proxy_main),
1487 dlg_stdeditbox_handler,
1488 I(offsetof(Config,proxy_port)),
1489 I(-1));
1490 c->generic.column = 1;
1491 ctrl_columns(s, 1, 100);
1492 ctrl_editbox(s, "Exclude Hosts/IPs", 'e', 100,
1493 HELPCTX(proxy_exclude),
1494 dlg_stdeditbox_handler,
1495 I(offsetof(Config,proxy_exclude_list)),
1496 I(sizeof(((Config *)0)->proxy_exclude_list)));
1497 ctrl_checkbox(s, "Consider proxying local host connections", 'x',
1498 HELPCTX(proxy_exclude),
1499 dlg_stdcheckbox_handler,
1500 I(offsetof(Config,even_proxy_localhost)));
1501 ctrl_radiobuttons(s, "Do DNS name lookup at proxy end:", 'd', 3,
1502 HELPCTX(proxy_dns),
1503 dlg_stdradiobutton_handler,
1504 I(offsetof(Config, proxy_dns)),
1505 "No", I(FORCE_OFF),
1506 "Auto", I(AUTO),
1507 "Yes", I(FORCE_ON), NULL);
1508 ctrl_editbox(s, "Username", 'u', 60,
1509 HELPCTX(proxy_auth),
1510 dlg_stdeditbox_handler,
1511 I(offsetof(Config,proxy_username)),
1512 I(sizeof(((Config *)0)->proxy_username)));
1513 c = ctrl_editbox(s, "Password", 'w', 60,
1514 HELPCTX(proxy_auth),
1515 dlg_stdeditbox_handler,
1516 I(offsetof(Config,proxy_password)),
1517 I(sizeof(((Config *)0)->proxy_password)));
1518 c->editbox.password = 1;
fe8abbf4 1519 ctrl_editbox(s, "Telnet command", 'm', 100,
1520 HELPCTX(proxy_command),
1521 dlg_stdeditbox_handler,
1522 I(offsetof(Config,proxy_telnet_command)),
1523 I(sizeof(((Config *)0)->proxy_telnet_command)));
fe8abbf4 1524 }
1525
1526 /*
1527 * The Telnet panel exists in the base config box, and in a
1528 * mid-session reconfig box _if_ we're using Telnet.
1529 */
1530 if (!midsession || protocol == PROT_TELNET) {
1531 /*
1532 * The Connection/Telnet panel.
1533 */
1534 ctrl_settitle(b, "Connection/Telnet",
1535 "Options controlling Telnet connections");
1536
fe8abbf4 1537 s = ctrl_getset(b, "Connection/Telnet", "protocol",
1538 "Telnet protocol adjustments");
1539
1540 if (!midsession) {
1541 ctrl_radiobuttons(s, "Handling of OLD_ENVIRON ambiguity:",
1542 NO_SHORTCUT, 2,
1543 HELPCTX(telnet_oldenviron),
1544 dlg_stdradiobutton_handler,
1545 I(offsetof(Config, rfc_environ)),
1546 "BSD (commonplace)", 'b', I(0),
1547 "RFC 1408 (unusual)", 'f', I(1), NULL);
1548 ctrl_radiobuttons(s, "Telnet negotiation mode:", 't', 2,
1549 HELPCTX(telnet_passive),
1550 dlg_stdradiobutton_handler,
1551 I(offsetof(Config, passive_telnet)),
1552 "Passive", I(1), "Active", I(0), NULL);
1553 }
76d3d354 1554 ctrl_checkbox(s, "Keyboard sends Telnet special commands", 'k',
fe8abbf4 1555 HELPCTX(telnet_specialkeys),
1556 dlg_stdcheckbox_handler,
1557 I(offsetof(Config,telnet_keyboard)));
76d3d354 1558 ctrl_checkbox(s, "Return key sends Telnet New Line instead of ^M",
1559 'm', HELPCTX(telnet_newline),
fe8abbf4 1560 dlg_stdcheckbox_handler,
1561 I(offsetof(Config,telnet_newline)));
1562 }
1563
1564 if (!midsession) {
1565
1566 /*
1567 * The Connection/Rlogin panel.
1568 */
1569 ctrl_settitle(b, "Connection/Rlogin",
1570 "Options controlling Rlogin connections");
1571
1572 s = ctrl_getset(b, "Connection/Rlogin", "data",
1573 "Data to send to the server");
fe8abbf4 1574 ctrl_editbox(s, "Local username:", 'l', 50,
1575 HELPCTX(rlogin_localuser),
1576 dlg_stdeditbox_handler, I(offsetof(Config,localusername)),
1577 I(sizeof(((Config *)0)->localusername)));
1578
1579 }
1580
1581 /*
fda2feb1 1582 * All the SSH stuff is omitted in PuTTYtel, or in a reconfig
1583 * when we're not doing SSH.
fe8abbf4 1584 */
1585
fda2feb1 1586 if (backends[3].name != NULL && (!midsession || protocol == PROT_SSH)) {
fe8abbf4 1587
1588 /*
1589 * The Connection/SSH panel.
1590 */
1591 ctrl_settitle(b, "Connection/SSH",
1592 "Options controlling SSH connections");
1593
e13bba36 1594 if (midsession && protcfginfo == 1) {
fda2feb1 1595 s = ctrl_getset(b, "Connection/SSH", "disclaimer", NULL);
1596 ctrl_text(s, "Nothing on this panel may be reconfigured in mid-"
1597 "session; it is only here so that sub-panels of it can "
1598 "exist without looking strange.", HELPCTX(no_help));
1599 }
1600
1601 if (!midsession) {
1602
1603 s = ctrl_getset(b, "Connection/SSH", "data",
1604 "Data to send to the server");
1605 ctrl_editbox(s, "Remote command:", 'r', 100,
1606 HELPCTX(ssh_command),
1607 dlg_stdeditbox_handler, I(offsetof(Config,remote_cmd)),
1608 I(sizeof(((Config *)0)->remote_cmd)));
1609
1610 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1611 ctrl_checkbox(s, "Don't allocate a pseudo-terminal", 'p',
1612 HELPCTX(ssh_nopty),
1613 dlg_stdcheckbox_handler,
1614 I(offsetof(Config,nopty)));
1615 ctrl_checkbox(s, "Don't start a shell or command at all", 'n',
1616 HELPCTX(ssh_noshell),
1617 dlg_stdcheckbox_handler,
1618 I(offsetof(Config,ssh_no_shell)));
e13bba36 1619 }
1620
1621 if (!midsession || protcfginfo != 1) {
1622 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1623
fda2feb1 1624 ctrl_checkbox(s, "Enable compression", 'e',
1625 HELPCTX(ssh_compress),
1626 dlg_stdcheckbox_handler,
1627 I(offsetof(Config,compression)));
e13bba36 1628 }
1629
1630 if (!midsession) {
1631 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1632
fda2feb1 1633 ctrl_radiobuttons(s, "Preferred SSH protocol version:", NO_SHORTCUT, 4,
1634 HELPCTX(ssh_protocol),
1635 dlg_stdradiobutton_handler,
1636 I(offsetof(Config, sshprot)),
1637 "1 only", 'l', I(0),
1638 "1", '1', I(1),
1639 "2", '2', I(2),
1640 "2 only", 'y', I(3), NULL);
e13bba36 1641 }
fda2feb1 1642
e13bba36 1643 if (!midsession || protcfginfo != 1) {
fda2feb1 1644 s = ctrl_getset(b, "Connection/SSH", "encryption", "Encryption options");
1645 c = ctrl_draglist(s, "Encryption cipher selection policy:", 's',
1646 HELPCTX(ssh_ciphers),
1647 cipherlist_handler, P(NULL));
1648 c->listbox.height = 6;
1649
2e85c969 1650 ctrl_checkbox(s, "Enable legacy use of single-DES in SSH-2", 'i',
bb524800 1651 HELPCTX(ssh_ciphers),
fda2feb1 1652 dlg_stdcheckbox_handler,
1653 I(offsetof(Config,ssh2_des_cbc)));
e6c1536e 1654 }
fe8abbf4 1655
e6c1536e 1656 /*
1657 * The Connection/SSH/Kex panel. (Owing to repeat key
f89c3294 1658 * exchange, this is all meaningful in mid-session _if_
2e85c969 1659 * we're using SSH-2 or haven't decided yet.)
e6c1536e 1660 */
f89c3294 1661 if (protcfginfo != 1) {
1662 ctrl_settitle(b, "Connection/SSH/Kex",
1663 "Options controlling SSH key exchange");
1664
1665 s = ctrl_getset(b, "Connection/SSH/Kex", "main",
1666 "Key exchange algorithm options");
2e077f2e 1667 c = ctrl_draglist(s, "Algorithm selection policy:", 's',
f89c3294 1668 HELPCTX(ssh_kexlist),
1669 kexlist_handler, P(NULL));
1670 c->listbox.height = 5;
1671
1672 s = ctrl_getset(b, "Connection/SSH/Kex", "repeat",
1673 "Options controlling key re-exchange");
1674
1675 ctrl_editbox(s, "Max minutes before rekey (0 for no limit)", 't', 20,
1676 HELPCTX(ssh_kex_repeat),
1677 dlg_stdeditbox_handler,
1678 I(offsetof(Config,ssh_rekey_time)),
1679 I(-1));
1680 ctrl_editbox(s, "Max data before rekey (0 for no limit)", 'x', 20,
1681 HELPCTX(ssh_kex_repeat),
1682 dlg_stdeditbox_handler,
1683 I(offsetof(Config,ssh_rekey_data)),
1684 I(16));
1685 ctrl_text(s, "(Use 1M for 1 megabyte, 1G for 1 gigabyte etc)",
1686 HELPCTX(ssh_kex_repeat));
1687 }
e6c1536e 1688
1689 if (!midsession) {
83e7d008 1690
fda2feb1 1691 /*
1692 * The Connection/SSH/Auth panel.
1693 */
1694 ctrl_settitle(b, "Connection/SSH/Auth",
1695 "Options controlling SSH authentication");
fe8abbf4 1696
fda2feb1 1697 s = ctrl_getset(b, "Connection/SSH/Auth", "methods",
1698 "Authentication methods");
2e85c969 1699 ctrl_checkbox(s, "Attempt TIS or CryptoCard auth (SSH-1)", 'm',
fda2feb1 1700 HELPCTX(ssh_auth_tis),
1701 dlg_stdcheckbox_handler,
1702 I(offsetof(Config,try_tis_auth)));
2e85c969 1703 ctrl_checkbox(s, "Attempt \"keyboard-interactive\" auth (SSH-2)",
fda2feb1 1704 'i', HELPCTX(ssh_auth_ki),
1705 dlg_stdcheckbox_handler,
1706 I(offsetof(Config,try_ki_auth)));
1707
1708 s = ctrl_getset(b, "Connection/SSH/Auth", "params",
1709 "Authentication parameters");
1710 ctrl_checkbox(s, "Allow agent forwarding", 'f',
1711 HELPCTX(ssh_auth_agentfwd),
1712 dlg_stdcheckbox_handler, I(offsetof(Config,agentfwd)));
2e85c969 1713 ctrl_checkbox(s, "Allow attempted changes of username in SSH-2", 'u',
fda2feb1 1714 HELPCTX(ssh_auth_changeuser),
1715 dlg_stdcheckbox_handler,
1716 I(offsetof(Config,change_username)));
1717 ctrl_filesel(s, "Private key file for authentication:", 'k',
1718 FILTER_KEY_FILES, FALSE, "Select private key file",
1719 HELPCTX(ssh_auth_privkey),
1720 dlg_stdfilesel_handler, I(offsetof(Config, keyfile)));
1721 }
fe8abbf4 1722
fda2feb1 1723 if (!midsession) {
05581745 1724 /*
1725 * The Connection/SSH/X11 panel.
1726 */
1727 ctrl_settitle(b, "Connection/SSH/X11",
1728 "Options controlling SSH X11 forwarding");
1729
1730 s = ctrl_getset(b, "Connection/SSH/X11", "x11", "X11 forwarding");
fda2feb1 1731 ctrl_checkbox(s, "Enable X11 forwarding", 'e',
1732 HELPCTX(ssh_tunnels_x11),
1733 dlg_stdcheckbox_handler,I(offsetof(Config,x11_forward)));
1734 ctrl_editbox(s, "X display location", 'x', 50,
1735 HELPCTX(ssh_tunnels_x11),
1736 dlg_stdeditbox_handler, I(offsetof(Config,x11_display)),
1737 I(sizeof(((Config *)0)->x11_display)));
1738 ctrl_radiobuttons(s, "Remote X11 authentication protocol", 'u', 2,
1739 HELPCTX(ssh_tunnels_x11auth),
1740 dlg_stdradiobutton_handler,
1741 I(offsetof(Config, x11_auth)),
1742 "MIT-Magic-Cookie-1", I(X11_MIT),
1743 "XDM-Authorization-1", I(X11_XDM), NULL);
1744 }
fe8abbf4 1745
05581745 1746 /*
1747 * The Tunnels panel _is_ still available in mid-session.
1748 */
1749 ctrl_settitle(b, "Connection/SSH/Tunnels",
1750 "Options controlling SSH port forwarding");
1751
fe8abbf4 1752 s = ctrl_getset(b, "Connection/SSH/Tunnels", "portfwd",
1753 "Port forwarding");
1754 ctrl_checkbox(s, "Local ports accept connections from other hosts",'t',
1755 HELPCTX(ssh_tunnels_portfwd_localhost),
1756 dlg_stdcheckbox_handler,
1757 I(offsetof(Config,lport_acceptall)));
2e85c969 1758 ctrl_checkbox(s, "Remote ports do the same (SSH-2 only)", 'p',
fe8abbf4 1759 HELPCTX(ssh_tunnels_portfwd_localhost),
1760 dlg_stdcheckbox_handler,
1761 I(offsetof(Config,rport_acceptall)));
1762
1763 ctrl_columns(s, 3, 55, 20, 25);
1764 c = ctrl_text(s, "Forwarded ports:", HELPCTX(ssh_tunnels_portfwd));
1765 c->generic.column = COLUMN_FIELD(0,2);
1766 /* You want to select from the list, _then_ hit Remove. So tab order
1767 * should be that way round. */
1768 pfd = (struct portfwd_data *)ctrl_alloc(b,sizeof(struct portfwd_data));
1769 pfd->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1770 HELPCTX(ssh_tunnels_portfwd),
1771 portfwd_handler, P(pfd));
1772 pfd->rembutton->generic.column = 2;
1773 pfd->rembutton->generic.tabdelay = 1;
1774 pfd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1775 HELPCTX(ssh_tunnels_portfwd),
1776 portfwd_handler, P(pfd));
1777 pfd->listbox->listbox.height = 3;
37dbf11c 1778 pfd->listbox->listbox.ncols = 2;
3d88e64d 1779 pfd->listbox->listbox.percentages = snewn(2, int);
37dbf11c 1780 pfd->listbox->listbox.percentages[0] = 20;
1781 pfd->listbox->listbox.percentages[1] = 80;
fe8abbf4 1782 ctrl_tabdelay(s, pfd->rembutton);
1783 ctrl_text(s, "Add new forwarded port:", HELPCTX(ssh_tunnels_portfwd));
1784 /* You want to enter source, destination and type, _then_ hit Add.
1785 * Again, we adjust the tab order to reflect this. */
1786 pfd->addbutton = ctrl_pushbutton(s, "Add", 'd',
1787 HELPCTX(ssh_tunnels_portfwd),
1788 portfwd_handler, P(pfd));
1789 pfd->addbutton->generic.column = 2;
1790 pfd->addbutton->generic.tabdelay = 1;
1791 pfd->sourcebox = ctrl_editbox(s, "Source port", 's', 40,
1792 HELPCTX(ssh_tunnels_portfwd),
1793 portfwd_handler, P(pfd), P(NULL));
1794 pfd->sourcebox->generic.column = 0;
1795 pfd->destbox = ctrl_editbox(s, "Destination", 'i', 67,
1796 HELPCTX(ssh_tunnels_portfwd),
1797 portfwd_handler, P(pfd), P(NULL));
820ebe3b 1798 pfd->direction = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
fe8abbf4 1799 HELPCTX(ssh_tunnels_portfwd),
1800 portfwd_handler, P(pfd),
1801 "Local", 'l', P(NULL),
820ebe3b 1802 "Remote", 'm', P(NULL),
1803 "Dynamic", 'y', P(NULL),
1804 NULL);
05581745 1805#ifndef NO_IPV6
22db244f 1806 pfd->addressfamily =
1807 ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
05581745 1808 HELPCTX(ssh_tunnels_portfwd_ipversion),
1809 portfwd_handler, P(pfd),
1810 "Auto", NO_SHORTCUT, I(ADDRTYPE_UNSPEC),
1811 "IPv4", NO_SHORTCUT, I(ADDRTYPE_IPV4),
05581745 1812 "IPv6", NO_SHORTCUT, I(ADDRTYPE_IPV6),
05581745 1813 NULL);
22db244f 1814#endif
fe8abbf4 1815 ctrl_tabdelay(s, pfd->addbutton);
1816 ctrl_columns(s, 1, 100);
1817
fda2feb1 1818 if (!midsession) {
1819 /*
1820 * The Connection/SSH/Bugs panel.
1821 */
1822 ctrl_settitle(b, "Connection/SSH/Bugs",
1823 "Workarounds for SSH server bugs");
1824
1825 s = ctrl_getset(b, "Connection/SSH/Bugs", "main",
1826 "Detection of known bugs in SSH servers");
2e85c969 1827 ctrl_droplist(s, "Chokes on SSH-1 ignore messages", 'i', 20,
fda2feb1 1828 HELPCTX(ssh_bugs_ignore1),
1829 sshbug_handler, I(offsetof(Config,sshbug_ignore1)));
2e85c969 1830 ctrl_droplist(s, "Refuses all SSH-1 password camouflage", 's', 20,
fda2feb1 1831 HELPCTX(ssh_bugs_plainpw1),
1832 sshbug_handler, I(offsetof(Config,sshbug_plainpw1)));
2e85c969 1833 ctrl_droplist(s, "Chokes on SSH-1 RSA authentication", 'r', 20,
fda2feb1 1834 HELPCTX(ssh_bugs_rsa1),
1835 sshbug_handler, I(offsetof(Config,sshbug_rsa1)));
2e85c969 1836 ctrl_droplist(s, "Miscomputes SSH-2 HMAC keys", 'm', 20,
fda2feb1 1837 HELPCTX(ssh_bugs_hmac2),
1838 sshbug_handler, I(offsetof(Config,sshbug_hmac2)));
2e85c969 1839 ctrl_droplist(s, "Miscomputes SSH-2 encryption keys", 'e', 20,
fda2feb1 1840 HELPCTX(ssh_bugs_derivekey2),
1841 sshbug_handler, I(offsetof(Config,sshbug_derivekey2)));
2e85c969 1842 ctrl_droplist(s, "Requires padding on SSH-2 RSA signatures", 'p', 20,
fda2feb1 1843 HELPCTX(ssh_bugs_rsapad2),
1844 sshbug_handler, I(offsetof(Config,sshbug_rsapad2)));
19f47a7d 1845 ctrl_droplist(s, "Misuses the session ID in SSH-2 PK auth", 'n', 20,
fda2feb1 1846 HELPCTX(ssh_bugs_pksessid2),
1847 sshbug_handler, I(offsetof(Config,sshbug_pksessid2)));
19f47a7d 1848 ctrl_droplist(s, "Handles SSH-2 key re-exchange badly", 'k', 20,
f382c87d 1849 HELPCTX(ssh_bugs_rekey2),
1850 sshbug_handler, I(offsetof(Config,sshbug_rekey2)));
fda2feb1 1851 }
fe8abbf4 1852 }
1853}