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