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