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