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