For local and dynamic port forwardings (i.e. the ones which listen
[u/mdw/putty] / config.c
CommitLineData
fe8abbf4 1/*
2 * config.c - the platform-independent parts of the PuTTY
3 * configuration box.
4 */
5
6#include <assert.h>
7#include <stdlib.h>
8
9#include "putty.h"
10#include "dialog.h"
11#include "storage.h"
12
13#define PRINTER_DISABLED_STRING "None (printing disabled)"
14
15static void protocolbuttons_handler(union control *ctrl, void *dlg,
16 void *data, int event)
17{
18 int button, defport;
19 Config *cfg = (Config *)data;
20 /*
21 * This function works just like the standard radio-button
22 * handler, except that it also has to change the setting of
23 * the port box. We expect the context parameter to point at
24 * the `union control' structure for the port box.
25 */
26 if (event == EVENT_REFRESH) {
27 for (button = 0; button < ctrl->radio.nbuttons; button++)
28 if (cfg->protocol == ctrl->radio.buttondata[button].i)
29 break;
30 /* We expected that `break' to happen, in all circumstances. */
31 assert(button < ctrl->radio.nbuttons);
32 dlg_radiobutton_set(ctrl, dlg, button);
33 } else if (event == EVENT_VALCHANGE) {
34 int oldproto = cfg->protocol;
35 button = dlg_radiobutton_get(ctrl, dlg);
36 assert(button >= 0 && button < ctrl->radio.nbuttons);
37 cfg->protocol = ctrl->radio.buttondata[button].i;
38 if (oldproto != cfg->protocol) {
39 defport = -1;
40 switch (cfg->protocol) {
41 case PROT_SSH: defport = 22; break;
42 case PROT_TELNET: defport = 23; break;
43 case PROT_RLOGIN: defport = 513; break;
44 }
45 if (defport > 0 && cfg->port != defport) {
46 cfg->port = defport;
47 dlg_refresh((union control *)ctrl->radio.context.p, dlg);
48 }
49 }
50 }
51}
52
53static void numeric_keypad_handler(union control *ctrl, void *dlg,
54 void *data, int event)
55{
56 int button;
57 Config *cfg = (Config *)data;
58 /*
59 * This function works much like the standard radio button
60 * handler, but it has to handle two fields in Config.
61 */
62 if (event == EVENT_REFRESH) {
63 if (cfg->nethack_keypad)
64 button = 2;
65 else if (cfg->app_keypad)
66 button = 1;
67 else
68 button = 0;
69 assert(button < ctrl->radio.nbuttons);
70 dlg_radiobutton_set(ctrl, dlg, button);
71 } else if (event == EVENT_VALCHANGE) {
72 button = dlg_radiobutton_get(ctrl, dlg);
73 assert(button >= 0 && button < ctrl->radio.nbuttons);
74 if (button == 2) {
75 cfg->app_keypad = FALSE;
76 cfg->nethack_keypad = TRUE;
77 } else {
78 cfg->app_keypad = (button != 0);
79 cfg->nethack_keypad = FALSE;
80 }
81 }
82}
83
84static void cipherlist_handler(union control *ctrl, void *dlg,
85 void *data, int event)
86{
87 Config *cfg = (Config *)data;
88 if (event == EVENT_REFRESH) {
89 int i;
90
91 static const struct { char *s; int c; } ciphers[] = {
92 { "3DES", CIPHER_3DES },
93 { "Blowfish", CIPHER_BLOWFISH },
94 { "DES", CIPHER_DES },
95 { "AES (SSH 2 only)", CIPHER_AES },
96 { "-- warn below here --", CIPHER_WARN }
97 };
98
99 /* Set up the "selected ciphers" box. */
100 /* (cipherlist assumed to contain all ciphers) */
101 dlg_update_start(ctrl, dlg);
102 dlg_listbox_clear(ctrl, dlg);
103 for (i = 0; i < CIPHER_MAX; i++) {
104 int c = cfg->ssh_cipherlist[i];
105 int j;
106 char *cstr = NULL;
107 for (j = 0; j < (sizeof ciphers) / (sizeof ciphers[0]); j++) {
108 if (ciphers[j].c == c) {
109 cstr = ciphers[j].s;
110 break;
111 }
112 }
4eaff8d4 113 dlg_listbox_addwithid(ctrl, dlg, cstr, c);
fe8abbf4 114 }
115 dlg_update_done(ctrl, dlg);
116
117 } else if (event == EVENT_VALCHANGE) {
118 int i;
119
120 /* Update array to match the list box. */
121 for (i=0; i < CIPHER_MAX; i++)
122 cfg->ssh_cipherlist[i] = dlg_listbox_getid(ctrl, dlg, i);
123
124 }
125}
126
83e7d008 127static void kexlist_handler(union control *ctrl, void *dlg,
128 void *data, int event)
129{
130 Config *cfg = (Config *)data;
131 if (event == EVENT_REFRESH) {
132 int i;
133
134 static const struct { char *s; int k; } kexes[] = {
135 { "Diffie-Hellman group 1", KEX_DHGROUP1 },
136 { "Diffie-Hellman group 14", KEX_DHGROUP14 },
137 { "Diffie-Hellman group exchange", KEX_DHGEX },
138 { "-- warn below here --", KEX_WARN }
139 };
140
141 /* Set up the "kex preference" box. */
142 /* (kexlist assumed to contain all algorithms) */
143 dlg_update_start(ctrl, dlg);
144 dlg_listbox_clear(ctrl, dlg);
145 for (i = 0; i < KEX_MAX; i++) {
146 int k = cfg->ssh_kexlist[i];
147 int j;
148 char *kstr = NULL;
149 for (j = 0; j < (sizeof kexes) / (sizeof kexes[0]); j++) {
150 if (kexes[j].k == k) {
151 kstr = kexes[j].s;
152 break;
153 }
154 }
155 dlg_listbox_addwithid(ctrl, dlg, kstr, k);
156 }
157 dlg_update_done(ctrl, dlg);
158
159 } else if (event == EVENT_VALCHANGE) {
160 int i;
161
162 /* Update array to match the list box. */
163 for (i=0; i < KEX_MAX; i++)
164 cfg->ssh_kexlist[i] = dlg_listbox_getid(ctrl, dlg, i);
165
166 }
167}
168
fe8abbf4 169static void printerbox_handler(union control *ctrl, void *dlg,
170 void *data, int event)
171{
172 Config *cfg = (Config *)data;
173 if (event == EVENT_REFRESH) {
174 int nprinters, i;
175 printer_enum *pe;
176
177 dlg_update_start(ctrl, dlg);
0f915619 178 /*
179 * Some backends may wish to disable the drop-down list on
180 * this edit box. Be prepared for this.
181 */
182 if (ctrl->editbox.has_list) {
183 dlg_listbox_clear(ctrl, dlg);
184 dlg_listbox_add(ctrl, dlg, PRINTER_DISABLED_STRING);
185 pe = printer_start_enum(&nprinters);
186 for (i = 0; i < nprinters; i++)
187 dlg_listbox_add(ctrl, dlg, printer_get_name(pe, i));
188 printer_finish_enum(pe);
189 }
fe8abbf4 190 dlg_editbox_set(ctrl, dlg,
191 (*cfg->printer ? cfg->printer :
192 PRINTER_DISABLED_STRING));
193 dlg_update_done(ctrl, dlg);
194 } else if (event == EVENT_VALCHANGE) {
195 dlg_editbox_get(ctrl, dlg, cfg->printer, sizeof(cfg->printer));
196 if (!strcmp(cfg->printer, PRINTER_DISABLED_STRING))
197 *cfg->printer = '\0';
198 }
199}
200
201static void codepage_handler(union control *ctrl, void *dlg,
202 void *data, int event)
203{
204 Config *cfg = (Config *)data;
205 if (event == EVENT_REFRESH) {
206 int i;
d4413bd2 207 const char *cp;
fe8abbf4 208 dlg_update_start(ctrl, dlg);
209 strcpy(cfg->line_codepage,
210 cp_name(decode_codepage(cfg->line_codepage)));
211 dlg_listbox_clear(ctrl, dlg);
212 for (i = 0; (cp = cp_enumerate(i)) != NULL; i++)
213 dlg_listbox_add(ctrl, dlg, cp);
214 dlg_editbox_set(ctrl, dlg, cfg->line_codepage);
215 dlg_update_done(ctrl, dlg);
216 } else if (event == EVENT_VALCHANGE) {
217 dlg_editbox_get(ctrl, dlg, cfg->line_codepage,
218 sizeof(cfg->line_codepage));
219 strcpy(cfg->line_codepage,
220 cp_name(decode_codepage(cfg->line_codepage)));
221 }
222}
223
224static void sshbug_handler(union control *ctrl, void *dlg,
225 void *data, int event)
226{
227 if (event == EVENT_REFRESH) {
228 dlg_update_start(ctrl, dlg);
229 dlg_listbox_clear(ctrl, dlg);
4eaff8d4 230 dlg_listbox_addwithid(ctrl, dlg, "Auto", AUTO);
231 dlg_listbox_addwithid(ctrl, dlg, "Off", FORCE_OFF);
232 dlg_listbox_addwithid(ctrl, dlg, "On", FORCE_ON);
fe8abbf4 233 switch (*(int *)ATOFFSET(data, ctrl->listbox.context.i)) {
234 case AUTO: dlg_listbox_select(ctrl, dlg, 0); break;
235 case FORCE_OFF: dlg_listbox_select(ctrl, dlg, 1); break;
236 case FORCE_ON: dlg_listbox_select(ctrl, dlg, 2); break;
237 }
238 dlg_update_done(ctrl, dlg);
239 } else if (event == EVENT_SELCHANGE) {
240 int i = dlg_listbox_index(ctrl, dlg);
241 if (i < 0)
242 i = AUTO;
243 else
244 i = dlg_listbox_getid(ctrl, dlg, i);
245 *(int *)ATOFFSET(data, ctrl->listbox.context.i) = i;
246 }
247}
248
4e6d4091 249#define SAVEDSESSION_LEN 2048
250
fe8abbf4 251struct sessionsaver_data {
252 union control *editbox, *listbox, *loadbutton, *savebutton, *delbutton;
253 union control *okbutton, *cancelbutton;
fe8abbf4 254 struct sesslist *sesslist;
2e155f47 255 int midsession;
fe8abbf4 256};
257
258/*
259 * Helper function to load the session selected in the list box, if
260 * any, as this is done in more than one place below. Returns 0 for
261 * failure.
262 */
263static int load_selected_session(struct sessionsaver_data *ssd,
4e6d4091 264 char *savedsession,
fe8abbf4 265 void *dlg, Config *cfg)
266{
267 int i = dlg_listbox_index(ssd->listbox, dlg);
268 int isdef;
269 if (i < 0) {
270 dlg_beep(dlg);
271 return 0;
272 }
273 isdef = !strcmp(ssd->sesslist->sessions[i], "Default Settings");
274 load_settings(ssd->sesslist->sessions[i], !isdef, cfg);
275 if (!isdef) {
4e6d4091 276 strncpy(savedsession, ssd->sesslist->sessions[i],
277 SAVEDSESSION_LEN);
278 savedsession[SAVEDSESSION_LEN-1] = '\0';
fe8abbf4 279 } else {
4e6d4091 280 savedsession[0] = '\0';
fe8abbf4 281 }
282 dlg_refresh(NULL, dlg);
283 /* Restore the selection, which might have been clobbered by
284 * changing the value of the edit box. */
285 dlg_listbox_select(ssd->listbox, dlg, i);
286 return 1;
287}
288
289static void sessionsaver_handler(union control *ctrl, void *dlg,
290 void *data, int event)
291{
292 Config *cfg = (Config *)data;
293 struct sessionsaver_data *ssd =
294 (struct sessionsaver_data *)ctrl->generic.context.p;
4e6d4091 295 char *savedsession;
296
297 /*
298 * The first time we're called in a new dialog, we must
299 * allocate space to store the current contents of the saved
300 * session edit box (since it must persist even when we switch
301 * panels, but is not part of the Config).
302 */
56b9b9a7 303 if (!ssd->editbox) {
304 savedsession = NULL;
305 } else if (!dlg_get_privdata(ssd->editbox, dlg)) {
4e6d4091 306 savedsession = (char *)
307 dlg_alloc_privdata(ssd->editbox, dlg, SAVEDSESSION_LEN);
308 savedsession[0] = '\0';
309 } else {
310 savedsession = dlg_get_privdata(ssd->editbox, dlg);
311 }
fe8abbf4 312
313 if (event == EVENT_REFRESH) {
314 if (ctrl == ssd->editbox) {
4e6d4091 315 dlg_editbox_set(ctrl, dlg, savedsession);
fe8abbf4 316 } else if (ctrl == ssd->listbox) {
317 int i;
318 dlg_update_start(ctrl, dlg);
319 dlg_listbox_clear(ctrl, dlg);
320 for (i = 0; i < ssd->sesslist->nsessions; i++)
321 dlg_listbox_add(ctrl, dlg, ssd->sesslist->sessions[i]);
322 dlg_update_done(ctrl, dlg);
323 }
324 } else if (event == EVENT_VALCHANGE) {
325 if (ctrl == ssd->editbox) {
4e6d4091 326 dlg_editbox_get(ctrl, dlg, savedsession,
327 SAVEDSESSION_LEN);
fe8abbf4 328 }
329 } else if (event == EVENT_ACTION) {
2e155f47 330 if (!ssd->midsession &&
331 (ctrl == ssd->listbox ||
332 (ssd->loadbutton && ctrl == ssd->loadbutton))) {
fe8abbf4 333 /*
334 * The user has double-clicked a session, or hit Load.
335 * We must load the selected session, and then
336 * terminate the configuration dialog _if_ there was a
337 * double-click on the list box _and_ that session
338 * contains a hostname.
339 */
4e6d4091 340 if (load_selected_session(ssd, savedsession, dlg, cfg) &&
fe8abbf4 341 (ctrl == ssd->listbox && cfg->host[0])) {
342 dlg_end(dlg, 1); /* it's all over, and succeeded */
343 }
344 } else if (ctrl == ssd->savebutton) {
4e6d4091 345 int isdef = !strcmp(savedsession, "Default Settings");
346 if (!savedsession[0]) {
8b0cb5aa 347 int i = dlg_listbox_index(ssd->listbox, dlg);
fe8abbf4 348 if (i < 0) {
349 dlg_beep(dlg);
350 return;
351 }
352 isdef = !strcmp(ssd->sesslist->sessions[i], "Default Settings");
353 if (!isdef) {
4e6d4091 354 strncpy(savedsession, ssd->sesslist->sessions[i],
355 SAVEDSESSION_LEN);
356 savedsession[SAVEDSESSION_LEN-1] = '\0';
fe8abbf4 357 } else {
4e6d4091 358 savedsession[0] = '\0';
fe8abbf4 359 }
360 }
3f935d5b 361 {
362 char *errmsg = save_settings(savedsession, !isdef, cfg);
363 if (errmsg) {
364 dlg_error_msg(dlg, errmsg);
365 sfree(errmsg);
366 }
367 }
fe8abbf4 368 get_sesslist(ssd->sesslist, FALSE);
369 get_sesslist(ssd->sesslist, TRUE);
370 dlg_refresh(ssd->editbox, dlg);
371 dlg_refresh(ssd->listbox, dlg);
2e155f47 372 } else if (!ssd->midsession &&
373 ssd->delbutton && ctrl == ssd->delbutton) {
6f87d111 374 int i = dlg_listbox_index(ssd->listbox, dlg);
fe8abbf4 375 if (i <= 0) {
376 dlg_beep(dlg);
377 } else {
378 del_settings(ssd->sesslist->sessions[i]);
379 get_sesslist(ssd->sesslist, FALSE);
380 get_sesslist(ssd->sesslist, TRUE);
381 dlg_refresh(ssd->listbox, dlg);
382 }
383 } else if (ctrl == ssd->okbutton) {
2e155f47 384 if (ssd->midsession) {
56b9b9a7 385 /* In a mid-session Change Settings, Apply is always OK. */
386 dlg_end(dlg, 1);
387 return;
388 }
fe8abbf4 389 /*
390 * Annoying special case. If the `Open' button is
391 * pressed while no host name is currently set, _and_
392 * the session list previously had the focus, _and_
393 * there was a session selected in that which had a
394 * valid host name in it, then load it and go.
395 */
0bd8d76d 396 if (dlg_last_focused(ctrl, dlg) == ssd->listbox && !*cfg->host) {
fe8abbf4 397 Config cfg2;
4e6d4091 398 if (!load_selected_session(ssd, savedsession, dlg, &cfg2)) {
fe8abbf4 399 dlg_beep(dlg);
400 return;
401 }
402 /* If at this point we have a valid session, go! */
403 if (*cfg2.host) {
404 *cfg = cfg2; /* structure copy */
6eaa8806 405 cfg->remote_cmd_ptr = cfg->remote_cmd; /* nasty */
fe8abbf4 406 dlg_end(dlg, 1);
407 } else
408 dlg_beep(dlg);
431c0a12 409 return;
fe8abbf4 410 }
411
412 /*
413 * Otherwise, do the normal thing: if we have a valid
414 * session, get going.
415 */
416 if (*cfg->host) {
417 dlg_end(dlg, 1);
418 } else
419 dlg_beep(dlg);
420 } else if (ctrl == ssd->cancelbutton) {
421 dlg_end(dlg, 0);
422 }
423 }
424}
425
426struct charclass_data {
427 union control *listbox, *editbox, *button;
428};
429
430static void charclass_handler(union control *ctrl, void *dlg,
431 void *data, int event)
432{
433 Config *cfg = (Config *)data;
434 struct charclass_data *ccd =
435 (struct charclass_data *)ctrl->generic.context.p;
436
437 if (event == EVENT_REFRESH) {
438 if (ctrl == ccd->listbox) {
439 int i;
440 dlg_update_start(ctrl, dlg);
441 dlg_listbox_clear(ctrl, dlg);
442 for (i = 0; i < 128; i++) {
443 char str[100];
444 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
445 (i >= 0x21 && i != 0x7F) ? i : ' ', cfg->wordness[i]);
446 dlg_listbox_add(ctrl, dlg, str);
447 }
448 dlg_update_done(ctrl, dlg);
449 }
450 } else if (event == EVENT_ACTION) {
451 if (ctrl == ccd->button) {
452 char str[100];
453 int i, n;
454 dlg_editbox_get(ccd->editbox, dlg, str, sizeof(str));
455 n = atoi(str);
456 for (i = 0; i < 128; i++) {
457 if (dlg_listbox_issel(ccd->listbox, dlg, i))
458 cfg->wordness[i] = n;
459 }
460 dlg_refresh(ccd->listbox, dlg);
461 }
462 }
463}
464
465struct colour_data {
18c2f87c 466 union control *listbox, *redit, *gedit, *bedit, *button;
fe8abbf4 467};
468
469static const char *const colours[] = {
470 "Default Foreground", "Default Bold Foreground",
471 "Default Background", "Default Bold Background",
472 "Cursor Text", "Cursor Colour",
473 "ANSI Black", "ANSI Black Bold",
474 "ANSI Red", "ANSI Red Bold",
475 "ANSI Green", "ANSI Green Bold",
476 "ANSI Yellow", "ANSI Yellow Bold",
477 "ANSI Blue", "ANSI Blue Bold",
478 "ANSI Magenta", "ANSI Magenta Bold",
479 "ANSI Cyan", "ANSI Cyan Bold",
480 "ANSI White", "ANSI White Bold"
481};
482
483static void colour_handler(union control *ctrl, void *dlg,
484 void *data, int event)
485{
486 Config *cfg = (Config *)data;
487 struct colour_data *cd =
488 (struct colour_data *)ctrl->generic.context.p;
489 int update = FALSE, r, g, b;
490
491 if (event == EVENT_REFRESH) {
492 if (ctrl == cd->listbox) {
493 int i;
494 dlg_update_start(ctrl, dlg);
495 dlg_listbox_clear(ctrl, dlg);
496 for (i = 0; i < lenof(colours); i++)
497 dlg_listbox_add(ctrl, dlg, colours[i]);
498 dlg_update_done(ctrl, dlg);
18c2f87c 499 dlg_editbox_set(cd->redit, dlg, "");
500 dlg_editbox_set(cd->gedit, dlg, "");
501 dlg_editbox_set(cd->bedit, dlg, "");
fe8abbf4 502 }
503 } else if (event == EVENT_SELCHANGE) {
504 if (ctrl == cd->listbox) {
505 /* The user has selected a colour. Update the RGB text. */
506 int i = dlg_listbox_index(ctrl, dlg);
507 if (i < 0) {
508 dlg_beep(dlg);
509 return;
510 }
511 r = cfg->colours[i][0];
512 g = cfg->colours[i][1];
513 b = cfg->colours[i][2];
514 update = TRUE;
515 }
18c2f87c 516 } else if (event == EVENT_VALCHANGE) {
517 if (ctrl == cd->redit || ctrl == cd->gedit || ctrl == cd->bedit) {
518 /* The user has changed the colour using the edit boxes. */
519 char buf[80];
520 int i, cval;
521
522 dlg_editbox_get(ctrl, dlg, buf, lenof(buf));
523 cval = atoi(buf) & 255;
524
525 i = dlg_listbox_index(cd->listbox, dlg);
526 if (i >= 0) {
527 if (ctrl == cd->redit)
528 cfg->colours[i][0] = cval;
529 else if (ctrl == cd->gedit)
530 cfg->colours[i][1] = cval;
531 else if (ctrl == cd->bedit)
532 cfg->colours[i][2] = cval;
533 }
534 }
fe8abbf4 535 } else if (event == EVENT_ACTION) {
536 if (ctrl == cd->button) {
537 int i = dlg_listbox_index(cd->listbox, dlg);
538 if (i < 0) {
539 dlg_beep(dlg);
540 return;
541 }
542 /*
543 * Start a colour selector, which will send us an
544 * EVENT_CALLBACK when it's finished and allow us to
545 * pick up the results.
546 */
547 dlg_coloursel_start(ctrl, dlg,
548 cfg->colours[i][0],
549 cfg->colours[i][1],
550 cfg->colours[i][2]);
551 }
552 } else if (event == EVENT_CALLBACK) {
553 if (ctrl == cd->button) {
554 int i = dlg_listbox_index(cd->listbox, dlg);
555 /*
556 * Collect the results of the colour selector. Will
557 * return nonzero on success, or zero if the colour
558 * selector did nothing (user hit Cancel, for example).
559 */
560 if (dlg_coloursel_results(ctrl, dlg, &r, &g, &b)) {
561 cfg->colours[i][0] = r;
562 cfg->colours[i][1] = g;
563 cfg->colours[i][2] = b;
564 update = TRUE;
565 }
566 }
567 }
568
569 if (update) {
570 char buf[40];
18c2f87c 571 sprintf(buf, "%d", r); dlg_editbox_set(cd->redit, dlg, buf);
572 sprintf(buf, "%d", g); dlg_editbox_set(cd->gedit, dlg, buf);
573 sprintf(buf, "%d", b); dlg_editbox_set(cd->bedit, dlg, buf);
fe8abbf4 574 }
575}
576
577struct environ_data {
578 union control *varbox, *valbox, *addbutton, *rembutton, *listbox;
579};
580
581static void environ_handler(union control *ctrl, void *dlg,
582 void *data, int event)
583{
584 Config *cfg = (Config *)data;
585 struct environ_data *ed =
586 (struct environ_data *)ctrl->generic.context.p;
587
588 if (event == EVENT_REFRESH) {
589 if (ctrl == ed->listbox) {
590 char *p = cfg->environmt;
591 dlg_update_start(ctrl, dlg);
592 dlg_listbox_clear(ctrl, dlg);
593 while (*p) {
594 dlg_listbox_add(ctrl, dlg, p);
595 p += strlen(p) + 1;
596 }
597 dlg_update_done(ctrl, dlg);
598 }
599 } else if (event == EVENT_ACTION) {
600 if (ctrl == ed->addbutton) {
601 char str[sizeof(cfg->environmt)];
602 char *p;
603 dlg_editbox_get(ed->varbox, dlg, str, sizeof(str)-1);
604 if (!*str) {
605 dlg_beep(dlg);
606 return;
607 }
608 p = str + strlen(str);
609 *p++ = '\t';
610 dlg_editbox_get(ed->valbox, dlg, p, sizeof(str)-1 - (p - str));
611 if (!*p) {
612 dlg_beep(dlg);
613 return;
614 }
615 p = cfg->environmt;
616 while (*p) {
617 while (*p)
618 p++;
619 p++;
620 }
621 if ((p - cfg->environmt) + strlen(str) + 2 <
622 sizeof(cfg->environmt)) {
623 strcpy(p, str);
624 p[strlen(str) + 1] = '\0';
625 dlg_listbox_add(ed->listbox, dlg, str);
626 dlg_editbox_set(ed->varbox, dlg, "");
627 dlg_editbox_set(ed->valbox, dlg, "");
628 } else {
629 dlg_error_msg(dlg, "Environment too big");
630 }
631 } else if (ctrl == ed->rembutton) {
632 int i = dlg_listbox_index(ed->listbox, dlg);
633 if (i < 0) {
634 dlg_beep(dlg);
635 } else {
636 char *p, *q;
637
638 dlg_listbox_del(ed->listbox, dlg, i);
639 p = cfg->environmt;
640 while (i > 0) {
641 if (!*p)
642 goto disaster;
643 while (*p)
644 p++;
645 p++;
646 i--;
647 }
648 q = p;
649 if (!*p)
650 goto disaster;
651 while (*p)
652 p++;
653 p++;
654 while (*p) {
655 while (*p)
656 *q++ = *p++;
657 *q++ = *p++;
658 }
659 *q = '\0';
660 disaster:;
661 }
662 }
663 }
664}
665
666struct portfwd_data {
667 union control *addbutton, *rembutton, *listbox;
668 union control *sourcebox, *destbox, *direction;
05581745 669 union control *addressfamily;
fe8abbf4 670};
671
672static void portfwd_handler(union control *ctrl, void *dlg,
673 void *data, int event)
674{
675 Config *cfg = (Config *)data;
676 struct portfwd_data *pfd =
677 (struct portfwd_data *)ctrl->generic.context.p;
678
679 if (event == EVENT_REFRESH) {
680 if (ctrl == pfd->listbox) {
681 char *p = cfg->portfwd;
682 dlg_update_start(ctrl, dlg);
683 dlg_listbox_clear(ctrl, dlg);
684 while (*p) {
685 dlg_listbox_add(ctrl, dlg, p);
686 p += strlen(p) + 1;
687 }
688 dlg_update_done(ctrl, dlg);
07e4d76d 689 } else if (ctrl == pfd->direction) {
690 /*
691 * Default is Local.
692 */
693 dlg_radiobutton_set(ctrl, dlg, 0);
05581745 694 } else if (ctrl == pfd->addressfamily) {
695 dlg_radiobutton_set(ctrl, dlg, 0);
fe8abbf4 696 }
697 } else if (event == EVENT_ACTION) {
698 if (ctrl == pfd->addbutton) {
699 char str[sizeof(cfg->portfwd)];
700 char *p;
05581745 701 int i, type;
702 int whichbutton;
703
704 i = 0;
705 whichbutton = dlg_radiobutton_get(pfd->addressfamily, dlg);
706 if (whichbutton == 1)
707 str[i++] = '4';
708 else if (whichbutton == 2)
709 str[i++] = '6';
710
711 whichbutton = dlg_radiobutton_get(pfd->direction, dlg);
820ebe3b 712 if (whichbutton == 0)
05581745 713 type = 'L';
820ebe3b 714 else if (whichbutton == 1)
05581745 715 type = 'R';
820ebe3b 716 else
05581745 717 type = 'D';
718 str[i++] = type;
719
720 dlg_editbox_get(pfd->sourcebox, dlg, str+i, sizeof(str) - i);
721 if (!str[2]) {
fe8abbf4 722 dlg_error_msg(dlg, "You need to specify a source port number");
723 return;
724 }
725 p = str + strlen(str);
05581745 726 if (type != 'D') {
820ebe3b 727 *p++ = '\t';
728 dlg_editbox_get(pfd->destbox, dlg, p,
729 sizeof(str)-1 - (p - str));
730 if (!*p || !strchr(p, ':')) {
731 dlg_error_msg(dlg,
732 "You need to specify a destination address\n"
733 "in the form \"host.name:port\"");
734 return;
735 }
736 } else
737 *p = '\0';
fe8abbf4 738 p = cfg->portfwd;
739 while (*p) {
740 while (*p)
741 p++;
742 p++;
743 }
744 if ((p - cfg->portfwd) + strlen(str) + 2 <
745 sizeof(cfg->portfwd)) {
746 strcpy(p, str);
747 p[strlen(str) + 1] = '\0';
748 dlg_listbox_add(pfd->listbox, dlg, str);
749 dlg_editbox_set(pfd->sourcebox, dlg, "");
750 dlg_editbox_set(pfd->destbox, dlg, "");
751 } else {
752 dlg_error_msg(dlg, "Too many forwardings");
753 }
754 } else if (ctrl == pfd->rembutton) {
755 int i = dlg_listbox_index(pfd->listbox, dlg);
756 if (i < 0)
757 dlg_beep(dlg);
758 else {
759 char *p, *q;
760
761 dlg_listbox_del(pfd->listbox, dlg, i);
762 p = cfg->portfwd;
763 while (i > 0) {
764 if (!*p)
765 goto disaster2;
766 while (*p)
767 p++;
768 p++;
769 i--;
770 }
771 q = p;
772 if (!*p)
773 goto disaster2;
774 while (*p)
775 p++;
776 p++;
777 while (*p) {
778 while (*p)
779 *q++ = *p++;
780 *q++ = *p++;
781 }
782 *q = '\0';
783 disaster2:;
784 }
785 }
786 }
787}
788
789void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
f89c3294 790 int midsession, int protocol, int protcfginfo)
fe8abbf4 791{
792 struct controlset *s;
793 struct sessionsaver_data *ssd;
794 struct charclass_data *ccd;
795 struct colour_data *cd;
796 struct environ_data *ed;
797 struct portfwd_data *pfd;
798 union control *c;
f6f450e2 799 char *str;
fe8abbf4 800
801 ssd = (struct sessionsaver_data *)
802 ctrl_alloc(b, sizeof(struct sessionsaver_data));
56b9b9a7 803 memset(ssd, 0, sizeof(*ssd));
2e155f47 804 ssd->midsession = midsession;
fe8abbf4 805
806 /*
807 * The standard panel that appears at the bottom of all panels:
808 * Open, Cancel, Apply etc.
809 */
810 s = ctrl_getset(b, "", "", "");
811 ctrl_columns(s, 5, 20, 20, 20, 20, 20);
812 ssd->okbutton = ctrl_pushbutton(s,
813 (midsession ? "Apply" : "Open"),
814 (char)(midsession ? 'a' : 'o'),
815 HELPCTX(no_help),
816 sessionsaver_handler, P(ssd));
817 ssd->okbutton->button.isdefault = TRUE;
818 ssd->okbutton->generic.column = 3;
819 ssd->cancelbutton = ctrl_pushbutton(s, "Cancel", 'c', HELPCTX(no_help),
820 sessionsaver_handler, P(ssd));
0bd8d76d 821 ssd->cancelbutton->button.iscancel = TRUE;
fe8abbf4 822 ssd->cancelbutton->generic.column = 4;
823 /* We carefully don't close the 5-column part, so that platform-
824 * specific add-ons can put extra buttons alongside Open and Cancel. */
825
826 /*
827 * The Session panel.
828 */
f6f450e2 829 str = dupprintf("Basic options for your %s session", appname);
830 ctrl_settitle(b, "Session", str);
831 sfree(str);
fe8abbf4 832
833 if (!midsession) {
834 s = ctrl_getset(b, "Session", "hostport",
835 "Specify your connection by host name or IP address");
836 ctrl_columns(s, 2, 75, 25);
837 c = ctrl_editbox(s, "Host Name (or IP address)", 'n', 100,
838 HELPCTX(session_hostname),
839 dlg_stdeditbox_handler, I(offsetof(Config,host)),
840 I(sizeof(((Config *)0)->host)));
841 c->generic.column = 0;
842 c = ctrl_editbox(s, "Port", 'p', 100, HELPCTX(session_hostname),
843 dlg_stdeditbox_handler,
844 I(offsetof(Config,port)), I(-1));
845 c->generic.column = 1;
846 ctrl_columns(s, 1, 100);
d9b15094 847 if (backends[3].name == NULL) {
fe8abbf4 848 ctrl_radiobuttons(s, "Protocol:", NO_SHORTCUT, 3,
849 HELPCTX(session_hostname),
850 protocolbuttons_handler, P(c),
851 "Raw", 'r', I(PROT_RAW),
852 "Telnet", 't', I(PROT_TELNET),
853 "Rlogin", 'i', I(PROT_RLOGIN),
854 NULL);
855 } else {
856 ctrl_radiobuttons(s, "Protocol:", NO_SHORTCUT, 4,
857 HELPCTX(session_hostname),
858 protocolbuttons_handler, P(c),
859 "Raw", 'r', I(PROT_RAW),
860 "Telnet", 't', I(PROT_TELNET),
861 "Rlogin", 'i', I(PROT_RLOGIN),
862 "SSH", 's', I(PROT_SSH),
863 NULL);
864 }
fe8abbf4 865 }
866
48c4dd7c 867 /*
868 * The Load/Save panel is available even in mid-session.
869 */
870 s = ctrl_getset(b, "Session", "savedsessions",
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)));
1381 s = ctrl_getset(b, "Connection", "ipversion",
1382 "Internet protocol version");
1383 ctrl_radiobuttons(s, NULL, NO_SHORTCUT,
1384#ifndef NO_IPV6
1385 3,
1386#else
1387 2,
1388#endif
1389 HELPCTX(connection_ipversion),
1390 dlg_stdradiobutton_handler,
1391 I(offsetof(Config, addressfamily)),
1392 "Auto", NO_SHORTCUT, I(ADDRTYPE_UNSPEC),
1393 "IPv4", NO_SHORTCUT, I(ADDRTYPE_IPV4),
1394#ifndef NO_IPV6
1395 "IPv6", NO_SHORTCUT, I(ADDRTYPE_IPV6),
1396#endif
1397 NULL);
1398 }
1399
1400 /*
1401 * A sub-panel Connection/Data, containing options that
1402 * decide on data to send to the server.
1403 */
1404 if (!midsession) {
1405 ctrl_settitle(b, "Connection/Data", "Data to send to the server");
1406
1407 s = ctrl_getset(b, "Connection/Data", "login",
1408 "Login details");
1409 ctrl_editbox(s, "Auto-login username", 'u', 50,
1410 HELPCTX(connection_username),
1411 dlg_stdeditbox_handler, I(offsetof(Config,username)),
1412 I(sizeof(((Config *)0)->username)));
1413
1414 s = ctrl_getset(b, "Connection/Data", "term",
1415 "Terminal details");
3e547dd8 1416 ctrl_editbox(s, "Terminal-type string", 't', 50,
1417 HELPCTX(connection_termtype),
1418 dlg_stdeditbox_handler, I(offsetof(Config,termtype)),
1419 I(sizeof(((Config *)0)->termtype)));
a5dd8467 1420 ctrl_editbox(s, "Terminal speeds", 's', 50,
1421 HELPCTX(connection_termspeed),
1422 dlg_stdeditbox_handler, I(offsetof(Config,termspeed)),
1423 I(sizeof(((Config *)0)->termspeed)));
73feed4f 1424
05581745 1425 s = ctrl_getset(b, "Connection/Data", "env",
1426 "Environment variables");
73feed4f 1427 ctrl_columns(s, 2, 80, 20);
1428 ed = (struct environ_data *)
1429 ctrl_alloc(b, sizeof(struct environ_data));
1430 ed->varbox = ctrl_editbox(s, "Variable", 'v', 60,
1431 HELPCTX(telnet_environ),
1432 environ_handler, P(ed), P(NULL));
1433 ed->varbox->generic.column = 0;
1434 ed->valbox = ctrl_editbox(s, "Value", 'l', 60,
1435 HELPCTX(telnet_environ),
1436 environ_handler, P(ed), P(NULL));
1437 ed->valbox->generic.column = 0;
1438 ed->addbutton = ctrl_pushbutton(s, "Add", 'd',
1439 HELPCTX(telnet_environ),
1440 environ_handler, P(ed));
1441 ed->addbutton->generic.column = 1;
1442 ed->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1443 HELPCTX(telnet_environ),
1444 environ_handler, P(ed));
1445 ed->rembutton->generic.column = 1;
1446 ctrl_columns(s, 1, 100);
1447 ed->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1448 HELPCTX(telnet_environ),
1449 environ_handler, P(ed));
1450 ed->listbox->listbox.height = 3;
1451 ed->listbox->listbox.ncols = 2;
1452 ed->listbox->listbox.percentages = snewn(2, int);
1453 ed->listbox->listbox.percentages[0] = 30;
1454 ed->listbox->listbox.percentages[1] = 70;
3e547dd8 1455 }
fe8abbf4 1456
fe8abbf4 1457 }
1458
1459 if (!midsession) {
1460 /*
1461 * The Connection/Proxy panel.
1462 */
1463 ctrl_settitle(b, "Connection/Proxy",
1464 "Options controlling proxy usage");
1465
10068a0b 1466 s = ctrl_getset(b, "Connection/Proxy", "basics", NULL);
1467 ctrl_radiobuttons(s, "Proxy type:", 't', 3,
fe8abbf4 1468 HELPCTX(proxy_type),
1469 dlg_stdradiobutton_handler,
1470 I(offsetof(Config, proxy_type)),
0f0a2507 1471 "None", I(PROXY_NONE),
10068a0b 1472 "SOCKS 4", I(PROXY_SOCKS4),
1473 "SOCKS 5", I(PROXY_SOCKS5),
0f0a2507 1474 "HTTP", I(PROXY_HTTP),
0f0a2507 1475 "Telnet", I(PROXY_TELNET),
fe8abbf4 1476 NULL);
1477 ctrl_columns(s, 2, 80, 20);
1478 c = ctrl_editbox(s, "Proxy hostname", 'y', 100,
1479 HELPCTX(proxy_main),
1480 dlg_stdeditbox_handler,
1481 I(offsetof(Config,proxy_host)),
1482 I(sizeof(((Config *)0)->proxy_host)));
1483 c->generic.column = 0;
1484 c = ctrl_editbox(s, "Port", 'p', 100,
1485 HELPCTX(proxy_main),
1486 dlg_stdeditbox_handler,
1487 I(offsetof(Config,proxy_port)),
1488 I(-1));
1489 c->generic.column = 1;
1490 ctrl_columns(s, 1, 100);
1491 ctrl_editbox(s, "Exclude Hosts/IPs", 'e', 100,
1492 HELPCTX(proxy_exclude),
1493 dlg_stdeditbox_handler,
1494 I(offsetof(Config,proxy_exclude_list)),
1495 I(sizeof(((Config *)0)->proxy_exclude_list)));
1496 ctrl_checkbox(s, "Consider proxying local host connections", 'x',
1497 HELPCTX(proxy_exclude),
1498 dlg_stdcheckbox_handler,
1499 I(offsetof(Config,even_proxy_localhost)));
1500 ctrl_radiobuttons(s, "Do DNS name lookup at proxy end:", 'd', 3,
1501 HELPCTX(proxy_dns),
1502 dlg_stdradiobutton_handler,
1503 I(offsetof(Config, proxy_dns)),
1504 "No", I(FORCE_OFF),
1505 "Auto", I(AUTO),
1506 "Yes", I(FORCE_ON), NULL);
1507 ctrl_editbox(s, "Username", 'u', 60,
1508 HELPCTX(proxy_auth),
1509 dlg_stdeditbox_handler,
1510 I(offsetof(Config,proxy_username)),
1511 I(sizeof(((Config *)0)->proxy_username)));
1512 c = ctrl_editbox(s, "Password", 'w', 60,
1513 HELPCTX(proxy_auth),
1514 dlg_stdeditbox_handler,
1515 I(offsetof(Config,proxy_password)),
1516 I(sizeof(((Config *)0)->proxy_password)));
1517 c->editbox.password = 1;
fe8abbf4 1518 ctrl_editbox(s, "Telnet command", 'm', 100,
1519 HELPCTX(proxy_command),
1520 dlg_stdeditbox_handler,
1521 I(offsetof(Config,proxy_telnet_command)),
1522 I(sizeof(((Config *)0)->proxy_telnet_command)));
fe8abbf4 1523 }
1524
1525 /*
1526 * The Telnet panel exists in the base config box, and in a
1527 * mid-session reconfig box _if_ we're using Telnet.
1528 */
1529 if (!midsession || protocol == PROT_TELNET) {
1530 /*
1531 * The Connection/Telnet panel.
1532 */
1533 ctrl_settitle(b, "Connection/Telnet",
1534 "Options controlling Telnet connections");
1535
fe8abbf4 1536 s = ctrl_getset(b, "Connection/Telnet", "protocol",
1537 "Telnet protocol adjustments");
1538
1539 if (!midsession) {
1540 ctrl_radiobuttons(s, "Handling of OLD_ENVIRON ambiguity:",
1541 NO_SHORTCUT, 2,
1542 HELPCTX(telnet_oldenviron),
1543 dlg_stdradiobutton_handler,
1544 I(offsetof(Config, rfc_environ)),
1545 "BSD (commonplace)", 'b', I(0),
1546 "RFC 1408 (unusual)", 'f', I(1), NULL);
1547 ctrl_radiobuttons(s, "Telnet negotiation mode:", 't', 2,
1548 HELPCTX(telnet_passive),
1549 dlg_stdradiobutton_handler,
1550 I(offsetof(Config, passive_telnet)),
1551 "Passive", I(1), "Active", I(0), NULL);
1552 }
76d3d354 1553 ctrl_checkbox(s, "Keyboard sends Telnet special commands", 'k',
fe8abbf4 1554 HELPCTX(telnet_specialkeys),
1555 dlg_stdcheckbox_handler,
1556 I(offsetof(Config,telnet_keyboard)));
76d3d354 1557 ctrl_checkbox(s, "Return key sends Telnet New Line instead of ^M",
1558 'm', HELPCTX(telnet_newline),
fe8abbf4 1559 dlg_stdcheckbox_handler,
1560 I(offsetof(Config,telnet_newline)));
1561 }
1562
1563 if (!midsession) {
1564
1565 /*
1566 * The Connection/Rlogin panel.
1567 */
1568 ctrl_settitle(b, "Connection/Rlogin",
1569 "Options controlling Rlogin connections");
1570
1571 s = ctrl_getset(b, "Connection/Rlogin", "data",
1572 "Data to send to the server");
fe8abbf4 1573 ctrl_editbox(s, "Local username:", 'l', 50,
1574 HELPCTX(rlogin_localuser),
1575 dlg_stdeditbox_handler, I(offsetof(Config,localusername)),
1576 I(sizeof(((Config *)0)->localusername)));
1577
1578 }
1579
1580 /*
fda2feb1 1581 * All the SSH stuff is omitted in PuTTYtel, or in a reconfig
1582 * when we're not doing SSH.
fe8abbf4 1583 */
1584
fda2feb1 1585 if (backends[3].name != NULL && (!midsession || protocol == PROT_SSH)) {
fe8abbf4 1586
1587 /*
1588 * The Connection/SSH panel.
1589 */
1590 ctrl_settitle(b, "Connection/SSH",
1591 "Options controlling SSH connections");
1592
e13bba36 1593 if (midsession && protcfginfo == 1) {
fda2feb1 1594 s = ctrl_getset(b, "Connection/SSH", "disclaimer", NULL);
1595 ctrl_text(s, "Nothing on this panel may be reconfigured in mid-"
1596 "session; it is only here so that sub-panels of it can "
1597 "exist without looking strange.", HELPCTX(no_help));
1598 }
1599
1600 if (!midsession) {
1601
1602 s = ctrl_getset(b, "Connection/SSH", "data",
1603 "Data to send to the server");
1604 ctrl_editbox(s, "Remote command:", 'r', 100,
1605 HELPCTX(ssh_command),
1606 dlg_stdeditbox_handler, I(offsetof(Config,remote_cmd)),
1607 I(sizeof(((Config *)0)->remote_cmd)));
1608
1609 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1610 ctrl_checkbox(s, "Don't allocate a pseudo-terminal", 'p',
1611 HELPCTX(ssh_nopty),
1612 dlg_stdcheckbox_handler,
1613 I(offsetof(Config,nopty)));
1614 ctrl_checkbox(s, "Don't start a shell or command at all", 'n',
1615 HELPCTX(ssh_noshell),
1616 dlg_stdcheckbox_handler,
1617 I(offsetof(Config,ssh_no_shell)));
e13bba36 1618 }
1619
1620 if (!midsession || protcfginfo != 1) {
1621 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1622
fda2feb1 1623 ctrl_checkbox(s, "Enable compression", 'e',
1624 HELPCTX(ssh_compress),
1625 dlg_stdcheckbox_handler,
1626 I(offsetof(Config,compression)));
e13bba36 1627 }
1628
1629 if (!midsession) {
1630 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1631
fda2feb1 1632 ctrl_radiobuttons(s, "Preferred SSH protocol version:", NO_SHORTCUT, 4,
1633 HELPCTX(ssh_protocol),
1634 dlg_stdradiobutton_handler,
1635 I(offsetof(Config, sshprot)),
1636 "1 only", 'l', I(0),
1637 "1", '1', I(1),
1638 "2", '2', I(2),
1639 "2 only", 'y', I(3), NULL);
e13bba36 1640 }
fda2feb1 1641
e13bba36 1642 if (!midsession || protcfginfo != 1) {
fda2feb1 1643 s = ctrl_getset(b, "Connection/SSH", "encryption", "Encryption options");
1644 c = ctrl_draglist(s, "Encryption cipher selection policy:", 's',
1645 HELPCTX(ssh_ciphers),
1646 cipherlist_handler, P(NULL));
1647 c->listbox.height = 6;
1648
1649 ctrl_checkbox(s, "Enable legacy use of single-DES in SSH 2", 'i',
bb524800 1650 HELPCTX(ssh_ciphers),
fda2feb1 1651 dlg_stdcheckbox_handler,
1652 I(offsetof(Config,ssh2_des_cbc)));
e6c1536e 1653 }
fe8abbf4 1654
e6c1536e 1655 /*
1656 * The Connection/SSH/Kex panel. (Owing to repeat key
f89c3294 1657 * exchange, this is all meaningful in mid-session _if_
1658 * we're using SSH2 or haven't decided yet.)
e6c1536e 1659 */
f89c3294 1660 if (protcfginfo != 1) {
1661 ctrl_settitle(b, "Connection/SSH/Kex",
1662 "Options controlling SSH key exchange");
1663
1664 s = ctrl_getset(b, "Connection/SSH/Kex", "main",
1665 "Key exchange algorithm options");
2e077f2e 1666 c = ctrl_draglist(s, "Algorithm selection policy:", 's',
f89c3294 1667 HELPCTX(ssh_kexlist),
1668 kexlist_handler, P(NULL));
1669 c->listbox.height = 5;
1670
1671 s = ctrl_getset(b, "Connection/SSH/Kex", "repeat",
1672 "Options controlling key re-exchange");
1673
1674 ctrl_editbox(s, "Max minutes before rekey (0 for no limit)", 't', 20,
1675 HELPCTX(ssh_kex_repeat),
1676 dlg_stdeditbox_handler,
1677 I(offsetof(Config,ssh_rekey_time)),
1678 I(-1));
1679 ctrl_editbox(s, "Max data before rekey (0 for no limit)", 'x', 20,
1680 HELPCTX(ssh_kex_repeat),
1681 dlg_stdeditbox_handler,
1682 I(offsetof(Config,ssh_rekey_data)),
1683 I(16));
1684 ctrl_text(s, "(Use 1M for 1 megabyte, 1G for 1 gigabyte etc)",
1685 HELPCTX(ssh_kex_repeat));
1686 }
e6c1536e 1687
1688 if (!midsession) {
83e7d008 1689
fda2feb1 1690 /*
1691 * The Connection/SSH/Auth panel.
1692 */
1693 ctrl_settitle(b, "Connection/SSH/Auth",
1694 "Options controlling SSH authentication");
fe8abbf4 1695
fda2feb1 1696 s = ctrl_getset(b, "Connection/SSH/Auth", "methods",
1697 "Authentication methods");
1698 ctrl_checkbox(s, "Attempt TIS or CryptoCard auth (SSH1)", 'm',
1699 HELPCTX(ssh_auth_tis),
1700 dlg_stdcheckbox_handler,
1701 I(offsetof(Config,try_tis_auth)));
1702 ctrl_checkbox(s, "Attempt \"keyboard-interactive\" auth (SSH2)",
1703 'i', HELPCTX(ssh_auth_ki),
1704 dlg_stdcheckbox_handler,
1705 I(offsetof(Config,try_ki_auth)));
1706
1707 s = ctrl_getset(b, "Connection/SSH/Auth", "params",
1708 "Authentication parameters");
1709 ctrl_checkbox(s, "Allow agent forwarding", 'f',
1710 HELPCTX(ssh_auth_agentfwd),
1711 dlg_stdcheckbox_handler, I(offsetof(Config,agentfwd)));
1712 ctrl_checkbox(s, "Allow attempted changes of username in SSH2", 'u',
1713 HELPCTX(ssh_auth_changeuser),
1714 dlg_stdcheckbox_handler,
1715 I(offsetof(Config,change_username)));
1716 ctrl_filesel(s, "Private key file for authentication:", 'k',
1717 FILTER_KEY_FILES, FALSE, "Select private key file",
1718 HELPCTX(ssh_auth_privkey),
1719 dlg_stdfilesel_handler, I(offsetof(Config, keyfile)));
1720 }
fe8abbf4 1721
fda2feb1 1722 if (!midsession) {
05581745 1723 /*
1724 * The Connection/SSH/X11 panel.
1725 */
1726 ctrl_settitle(b, "Connection/SSH/X11",
1727 "Options controlling SSH X11 forwarding");
1728
1729 s = ctrl_getset(b, "Connection/SSH/X11", "x11", "X11 forwarding");
fda2feb1 1730 ctrl_checkbox(s, "Enable X11 forwarding", 'e',
1731 HELPCTX(ssh_tunnels_x11),
1732 dlg_stdcheckbox_handler,I(offsetof(Config,x11_forward)));
1733 ctrl_editbox(s, "X display location", 'x', 50,
1734 HELPCTX(ssh_tunnels_x11),
1735 dlg_stdeditbox_handler, I(offsetof(Config,x11_display)),
1736 I(sizeof(((Config *)0)->x11_display)));
1737 ctrl_radiobuttons(s, "Remote X11 authentication protocol", 'u', 2,
1738 HELPCTX(ssh_tunnels_x11auth),
1739 dlg_stdradiobutton_handler,
1740 I(offsetof(Config, x11_auth)),
1741 "MIT-Magic-Cookie-1", I(X11_MIT),
1742 "XDM-Authorization-1", I(X11_XDM), NULL);
1743 }
fe8abbf4 1744
05581745 1745 /*
1746 * The Tunnels panel _is_ still available in mid-session.
1747 */
1748 ctrl_settitle(b, "Connection/SSH/Tunnels",
1749 "Options controlling SSH port forwarding");
1750
fe8abbf4 1751 s = ctrl_getset(b, "Connection/SSH/Tunnels", "portfwd",
1752 "Port forwarding");
1753 ctrl_checkbox(s, "Local ports accept connections from other hosts",'t',
1754 HELPCTX(ssh_tunnels_portfwd_localhost),
1755 dlg_stdcheckbox_handler,
1756 I(offsetof(Config,lport_acceptall)));
1757 ctrl_checkbox(s, "Remote ports do the same (SSH v2 only)", 'p',
1758 HELPCTX(ssh_tunnels_portfwd_localhost),
1759 dlg_stdcheckbox_handler,
1760 I(offsetof(Config,rport_acceptall)));
1761
1762 ctrl_columns(s, 3, 55, 20, 25);
1763 c = ctrl_text(s, "Forwarded ports:", HELPCTX(ssh_tunnels_portfwd));
1764 c->generic.column = COLUMN_FIELD(0,2);
1765 /* You want to select from the list, _then_ hit Remove. So tab order
1766 * should be that way round. */
1767 pfd = (struct portfwd_data *)ctrl_alloc(b,sizeof(struct portfwd_data));
1768 pfd->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1769 HELPCTX(ssh_tunnels_portfwd),
1770 portfwd_handler, P(pfd));
1771 pfd->rembutton->generic.column = 2;
1772 pfd->rembutton->generic.tabdelay = 1;
1773 pfd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1774 HELPCTX(ssh_tunnels_portfwd),
1775 portfwd_handler, P(pfd));
1776 pfd->listbox->listbox.height = 3;
37dbf11c 1777 pfd->listbox->listbox.ncols = 2;
3d88e64d 1778 pfd->listbox->listbox.percentages = snewn(2, int);
37dbf11c 1779 pfd->listbox->listbox.percentages[0] = 20;
1780 pfd->listbox->listbox.percentages[1] = 80;
fe8abbf4 1781 ctrl_tabdelay(s, pfd->rembutton);
1782 ctrl_text(s, "Add new forwarded port:", HELPCTX(ssh_tunnels_portfwd));
1783 /* You want to enter source, destination and type, _then_ hit Add.
1784 * Again, we adjust the tab order to reflect this. */
1785 pfd->addbutton = ctrl_pushbutton(s, "Add", 'd',
1786 HELPCTX(ssh_tunnels_portfwd),
1787 portfwd_handler, P(pfd));
1788 pfd->addbutton->generic.column = 2;
1789 pfd->addbutton->generic.tabdelay = 1;
1790 pfd->sourcebox = ctrl_editbox(s, "Source port", 's', 40,
1791 HELPCTX(ssh_tunnels_portfwd),
1792 portfwd_handler, P(pfd), P(NULL));
1793 pfd->sourcebox->generic.column = 0;
1794 pfd->destbox = ctrl_editbox(s, "Destination", 'i', 67,
1795 HELPCTX(ssh_tunnels_portfwd),
1796 portfwd_handler, P(pfd), P(NULL));
820ebe3b 1797 pfd->direction = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
fe8abbf4 1798 HELPCTX(ssh_tunnels_portfwd),
1799 portfwd_handler, P(pfd),
1800 "Local", 'l', P(NULL),
820ebe3b 1801 "Remote", 'm', P(NULL),
1802 "Dynamic", 'y', P(NULL),
1803 NULL);
05581745 1804 pfd->addressfamily =
1805 ctrl_radiobuttons(s, NULL, NO_SHORTCUT,
1806#ifndef NO_IPV6
1807 3,
1808#else
1809 2,
1810#endif
1811 HELPCTX(ssh_tunnels_portfwd_ipversion),
1812 portfwd_handler, P(pfd),
1813 "Auto", NO_SHORTCUT, I(ADDRTYPE_UNSPEC),
1814 "IPv4", NO_SHORTCUT, I(ADDRTYPE_IPV4),
1815#ifndef NO_IPV6
1816 "IPv6", NO_SHORTCUT, I(ADDRTYPE_IPV6),
1817#endif
1818 NULL);
fe8abbf4 1819 ctrl_tabdelay(s, pfd->addbutton);
1820 ctrl_columns(s, 1, 100);
1821
fda2feb1 1822 if (!midsession) {
1823 /*
1824 * The Connection/SSH/Bugs panel.
1825 */
1826 ctrl_settitle(b, "Connection/SSH/Bugs",
1827 "Workarounds for SSH server bugs");
1828
1829 s = ctrl_getset(b, "Connection/SSH/Bugs", "main",
1830 "Detection of known bugs in SSH servers");
1831 ctrl_droplist(s, "Chokes on SSH1 ignore messages", 'i', 20,
1832 HELPCTX(ssh_bugs_ignore1),
1833 sshbug_handler, I(offsetof(Config,sshbug_ignore1)));
1834 ctrl_droplist(s, "Refuses all SSH1 password camouflage", 's', 20,
1835 HELPCTX(ssh_bugs_plainpw1),
1836 sshbug_handler, I(offsetof(Config,sshbug_plainpw1)));
1837 ctrl_droplist(s, "Chokes on SSH1 RSA authentication", 'r', 20,
1838 HELPCTX(ssh_bugs_rsa1),
1839 sshbug_handler, I(offsetof(Config,sshbug_rsa1)));
1840 ctrl_droplist(s, "Miscomputes SSH2 HMAC keys", 'm', 20,
1841 HELPCTX(ssh_bugs_hmac2),
1842 sshbug_handler, I(offsetof(Config,sshbug_hmac2)));
1843 ctrl_droplist(s, "Miscomputes SSH2 encryption keys", 'e', 20,
1844 HELPCTX(ssh_bugs_derivekey2),
1845 sshbug_handler, I(offsetof(Config,sshbug_derivekey2)));
1846 ctrl_droplist(s, "Requires padding on SSH2 RSA signatures", 'p', 20,
1847 HELPCTX(ssh_bugs_rsapad2),
1848 sshbug_handler, I(offsetof(Config,sshbug_rsapad2)));
1849 ctrl_droplist(s, "Misuses the session ID in PK auth", 'n', 20,
1850 HELPCTX(ssh_bugs_pksessid2),
1851 sshbug_handler, I(offsetof(Config,sshbug_pksessid2)));
1852 }
fe8abbf4 1853 }
1854}