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