2 * config.c - the platform-independent parts of the PuTTY
13 #define PRINTER_DISABLED_STRING "None (printing disabled)"
15 static void protocolbuttons_handler(union control *ctrl, void *dlg,
16 void *data, int event)
19 Config *cfg = (Config *)data;
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.
26 if (event == EVENT_REFRESH) {
27 for (button = 0; button < ctrl->radio.nbuttons; button++)
28 if (cfg->protocol == ctrl->radio.buttondata[button].i)
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) {
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;
45 if (defport > 0 && cfg->port != defport) {
47 dlg_refresh((union control *)ctrl->radio.context.p, dlg);
53 static void loggingbuttons_handler(union control *ctrl, void *dlg,
54 void *data, int event)
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.
62 if (event == EVENT_REFRESH) {
63 for (button = 0; button < ctrl->radio.nbuttons; button++)
64 if (cfg->logtype == ctrl->radio.buttondata[button].i)
67 /* We fell off the end, so we lack the configured logging type */
68 if (button == ctrl->radio.nbuttons) {
70 cfg->logtype=LGTYP_NONE;
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;
80 static void numeric_keypad_handler(union control *ctrl, void *dlg,
81 void *data, int event)
84 Config *cfg = (Config *)data;
86 * This function works much like the standard radio button
87 * handler, but it has to handle two fields in Config.
89 if (event == EVENT_REFRESH) {
90 if (cfg->nethack_keypad)
92 else if (cfg->app_keypad)
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);
102 cfg->app_keypad = FALSE;
103 cfg->nethack_keypad = TRUE;
105 cfg->app_keypad = (button != 0);
106 cfg->nethack_keypad = FALSE;
111 static void cipherlist_handler(union control *ctrl, void *dlg,
112 void *data, int event)
114 Config *cfg = (Config *)data;
115 if (event == EVENT_REFRESH) {
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 }
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];
135 for (j = 0; j < (sizeof ciphers) / (sizeof ciphers[0]); j++) {
136 if (ciphers[j].c == c) {
141 dlg_listbox_addwithid(ctrl, dlg, cstr, c);
143 dlg_update_done(ctrl, dlg);
145 } else if (event == EVENT_VALCHANGE) {
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);
155 static void kexlist_handler(union control *ctrl, void *dlg,
156 void *data, int event)
158 Config *cfg = (Config *)data;
159 if (event == EVENT_REFRESH) {
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 }
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];
177 for (j = 0; j < (sizeof kexes) / (sizeof kexes[0]); j++) {
178 if (kexes[j].k == k) {
183 dlg_listbox_addwithid(ctrl, dlg, kstr, k);
185 dlg_update_done(ctrl, dlg);
187 } else if (event == EVENT_VALCHANGE) {
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);
197 static void printerbox_handler(union control *ctrl, void *dlg,
198 void *data, int event)
200 Config *cfg = (Config *)data;
201 if (event == EVENT_REFRESH) {
205 dlg_update_start(ctrl, dlg);
207 * Some backends may wish to disable the drop-down list on
208 * this edit box. Be prepared for this.
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);
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';
229 static void codepage_handler(union control *ctrl, void *dlg,
230 void *data, int event)
232 Config *cfg = (Config *)data;
233 if (event == EVENT_REFRESH) {
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)));
252 static void sshbug_handler(union control *ctrl, void *dlg,
253 void *data, int event)
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;
266 dlg_update_done(ctrl, dlg);
267 } else if (event == EVENT_SELCHANGE) {
268 int i = dlg_listbox_index(ctrl, dlg);
272 i = dlg_listbox_getid(ctrl, dlg, i);
273 *(int *)ATOFFSET(data, ctrl->listbox.context.i) = i;
277 #define SAVEDSESSION_LEN 2048
279 struct sessionsaver_data {
280 union control *editbox, *listbox, *loadbutton, *savebutton, *delbutton;
281 union control *okbutton, *cancelbutton;
282 struct sesslist sesslist;
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
291 static int load_selected_session(struct sessionsaver_data *ssd,
293 void *dlg, Config *cfg)
295 int i = dlg_listbox_index(ssd->listbox, dlg);
301 isdef = !strcmp(ssd->sesslist.sessions[i], "Default Settings");
302 load_settings(ssd->sesslist.sessions[i], !isdef, cfg);
304 strncpy(savedsession, ssd->sesslist.sessions[i],
306 savedsession[SAVEDSESSION_LEN-1] = '\0';
308 savedsession[0] = '\0';
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);
317 static void sessionsaver_handler(union control *ctrl, void *dlg,
318 void *data, int event)
320 Config *cfg = (Config *)data;
321 struct sessionsaver_data *ssd =
322 (struct sessionsaver_data *)ctrl->generic.context.p;
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).
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';
338 savedsession = dlg_get_privdata(ssd->editbox, dlg);
341 if (event == EVENT_REFRESH) {
342 if (ctrl == ssd->editbox) {
343 dlg_editbox_set(ctrl, dlg, savedsession);
344 } else if (ctrl == ssd->listbox) {
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);
352 } else if (event == EVENT_VALCHANGE) {
353 int top, bottom, halfway, i;
354 if (ctrl == ssd->editbox) {
355 dlg_editbox_get(ctrl, dlg, savedsession,
357 top = ssd->sesslist.nsessions;
359 while (top-bottom > 1) {
360 halfway = (top+bottom)/2;
361 i = strcmp(savedsession, ssd->sesslist.sessions[halfway]);
368 if (top == ssd->sesslist.nsessions) {
371 dlg_listbox_select(ssd->listbox, dlg, top);
373 } else if (event == EVENT_ACTION) {
374 if (!ssd->midsession &&
375 (ctrl == ssd->listbox ||
376 (ssd->loadbutton && ctrl == ssd->loadbutton))) {
378 * The user has double-clicked a session, or hit Load.
379 * We must load the selected session, and then
380 * terminate the configuration dialog _if_ there was a
381 * double-click on the list box _and_ that session
382 * contains a hostname.
384 if (load_selected_session(ssd, savedsession, dlg, cfg) &&
385 (ctrl == ssd->listbox && cfg->host[0])) {
386 dlg_end(dlg, 1); /* it's all over, and succeeded */
388 } else if (ctrl == ssd->savebutton) {
389 int isdef = !strcmp(savedsession, "Default Settings");
390 if (!savedsession[0]) {
391 int i = dlg_listbox_index(ssd->listbox, dlg);
396 isdef = !strcmp(ssd->sesslist.sessions[i], "Default Settings");
398 strncpy(savedsession, ssd->sesslist.sessions[i],
400 savedsession[SAVEDSESSION_LEN-1] = '\0';
402 savedsession[0] = '\0';
406 char *errmsg = save_settings(savedsession, !isdef, cfg);
408 dlg_error_msg(dlg, errmsg);
412 get_sesslist(&ssd->sesslist, FALSE);
413 get_sesslist(&ssd->sesslist, TRUE);
414 dlg_refresh(ssd->editbox, dlg);
415 dlg_refresh(ssd->listbox, dlg);
416 } else if (!ssd->midsession &&
417 ssd->delbutton && ctrl == ssd->delbutton) {
418 int i = dlg_listbox_index(ssd->listbox, dlg);
422 del_settings(ssd->sesslist.sessions[i]);
423 get_sesslist(&ssd->sesslist, FALSE);
424 get_sesslist(&ssd->sesslist, TRUE);
425 dlg_refresh(ssd->listbox, dlg);
427 } else if (ctrl == ssd->okbutton) {
428 if (ssd->midsession) {
429 /* In a mid-session Change Settings, Apply is always OK. */
434 * Annoying special case. If the `Open' button is
435 * pressed while no host name is currently set, _and_
436 * the session list previously had the focus, _and_
437 * there was a session selected in that which had a
438 * valid host name in it, then load it and go.
440 if (dlg_last_focused(ctrl, dlg) == ssd->listbox && !*cfg->host) {
442 if (!load_selected_session(ssd, savedsession, dlg, &cfg2)) {
446 /* If at this point we have a valid session, go! */
448 *cfg = cfg2; /* structure copy */
449 cfg->remote_cmd_ptr = NULL;
457 * Otherwise, do the normal thing: if we have a valid
458 * session, get going.
464 } else if (ctrl == ssd->cancelbutton) {
470 struct charclass_data {
471 union control *listbox, *editbox, *button;
474 static void charclass_handler(union control *ctrl, void *dlg,
475 void *data, int event)
477 Config *cfg = (Config *)data;
478 struct charclass_data *ccd =
479 (struct charclass_data *)ctrl->generic.context.p;
481 if (event == EVENT_REFRESH) {
482 if (ctrl == ccd->listbox) {
484 dlg_update_start(ctrl, dlg);
485 dlg_listbox_clear(ctrl, dlg);
486 for (i = 0; i < 128; i++) {
488 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
489 (i >= 0x21 && i != 0x7F) ? i : ' ', cfg->wordness[i]);
490 dlg_listbox_add(ctrl, dlg, str);
492 dlg_update_done(ctrl, dlg);
494 } else if (event == EVENT_ACTION) {
495 if (ctrl == ccd->button) {
498 dlg_editbox_get(ccd->editbox, dlg, str, sizeof(str));
500 for (i = 0; i < 128; i++) {
501 if (dlg_listbox_issel(ccd->listbox, dlg, i))
502 cfg->wordness[i] = n;
504 dlg_refresh(ccd->listbox, dlg);
510 union control *listbox, *redit, *gedit, *bedit, *button;
513 static const char *const colours[] = {
514 "Default Foreground", "Default Bold Foreground",
515 "Default Background", "Default Bold Background",
516 "Cursor Text", "Cursor Colour",
517 "ANSI Black", "ANSI Black Bold",
518 "ANSI Red", "ANSI Red Bold",
519 "ANSI Green", "ANSI Green Bold",
520 "ANSI Yellow", "ANSI Yellow Bold",
521 "ANSI Blue", "ANSI Blue Bold",
522 "ANSI Magenta", "ANSI Magenta Bold",
523 "ANSI Cyan", "ANSI Cyan Bold",
524 "ANSI White", "ANSI White Bold"
527 static void colour_handler(union control *ctrl, void *dlg,
528 void *data, int event)
530 Config *cfg = (Config *)data;
531 struct colour_data *cd =
532 (struct colour_data *)ctrl->generic.context.p;
533 int update = FALSE, r, g, b;
535 if (event == EVENT_REFRESH) {
536 if (ctrl == cd->listbox) {
538 dlg_update_start(ctrl, dlg);
539 dlg_listbox_clear(ctrl, dlg);
540 for (i = 0; i < lenof(colours); i++)
541 dlg_listbox_add(ctrl, dlg, colours[i]);
542 dlg_update_done(ctrl, dlg);
543 dlg_editbox_set(cd->redit, dlg, "");
544 dlg_editbox_set(cd->gedit, dlg, "");
545 dlg_editbox_set(cd->bedit, dlg, "");
547 } else if (event == EVENT_SELCHANGE) {
548 if (ctrl == cd->listbox) {
549 /* The user has selected a colour. Update the RGB text. */
550 int i = dlg_listbox_index(ctrl, dlg);
555 r = cfg->colours[i][0];
556 g = cfg->colours[i][1];
557 b = cfg->colours[i][2];
560 } else if (event == EVENT_VALCHANGE) {
561 if (ctrl == cd->redit || ctrl == cd->gedit || ctrl == cd->bedit) {
562 /* The user has changed the colour using the edit boxes. */
566 dlg_editbox_get(ctrl, dlg, buf, lenof(buf));
567 cval = atoi(buf) & 255;
569 i = dlg_listbox_index(cd->listbox, dlg);
571 if (ctrl == cd->redit)
572 cfg->colours[i][0] = cval;
573 else if (ctrl == cd->gedit)
574 cfg->colours[i][1] = cval;
575 else if (ctrl == cd->bedit)
576 cfg->colours[i][2] = cval;
579 } else if (event == EVENT_ACTION) {
580 if (ctrl == cd->button) {
581 int i = dlg_listbox_index(cd->listbox, dlg);
587 * Start a colour selector, which will send us an
588 * EVENT_CALLBACK when it's finished and allow us to
589 * pick up the results.
591 dlg_coloursel_start(ctrl, dlg,
596 } else if (event == EVENT_CALLBACK) {
597 if (ctrl == cd->button) {
598 int i = dlg_listbox_index(cd->listbox, dlg);
600 * Collect the results of the colour selector. Will
601 * return nonzero on success, or zero if the colour
602 * selector did nothing (user hit Cancel, for example).
604 if (dlg_coloursel_results(ctrl, dlg, &r, &g, &b)) {
605 cfg->colours[i][0] = r;
606 cfg->colours[i][1] = g;
607 cfg->colours[i][2] = b;
615 sprintf(buf, "%d", r); dlg_editbox_set(cd->redit, dlg, buf);
616 sprintf(buf, "%d", g); dlg_editbox_set(cd->gedit, dlg, buf);
617 sprintf(buf, "%d", b); dlg_editbox_set(cd->bedit, dlg, buf);
621 struct ttymodes_data {
622 union control *modelist, *valradio, *valbox;
623 union control *addbutton, *rembutton, *listbox;
626 static void ttymodes_handler(union control *ctrl, void *dlg,
627 void *data, int event)
629 Config *cfg = (Config *)data;
630 struct ttymodes_data *td =
631 (struct ttymodes_data *)ctrl->generic.context.p;
633 if (event == EVENT_REFRESH) {
634 if (ctrl == td->listbox) {
635 char *p = cfg->ttymodes;
636 dlg_update_start(ctrl, dlg);
637 dlg_listbox_clear(ctrl, dlg);
639 int tabpos = strchr(p, '\t') - p;
640 char *disp = dupprintf("%.*s\t%s", tabpos, p,
641 (p[tabpos+1] == 'A') ? "(auto)" :
643 dlg_listbox_add(ctrl, dlg, disp);
647 dlg_update_done(ctrl, dlg);
648 } else if (ctrl == td->modelist) {
650 dlg_update_start(ctrl, dlg);
651 dlg_listbox_clear(ctrl, dlg);
652 for (i = 0; ttymodes[i]; i++)
653 dlg_listbox_add(ctrl, dlg, ttymodes[i]);
654 dlg_listbox_select(ctrl, dlg, 0); /* *shrug* */
655 dlg_update_done(ctrl, dlg);
656 } else if (ctrl == td->valradio) {
657 dlg_radiobutton_set(ctrl, dlg, 0);
659 } else if (event == EVENT_ACTION) {
660 if (ctrl == td->addbutton) {
661 int ind = dlg_listbox_index(td->modelist, dlg);
663 char type = dlg_radiobutton_get(td->valradio, dlg) ? 'V' : 'A';
665 char *p, str[lenof(cfg->ttymodes)];
666 /* Construct new entry */
667 memset(str, 0, lenof(str));
668 strncpy(str, ttymodes[ind], lenof(str)-3);
674 dlg_editbox_get(td->valbox, dlg, str+slen, lenof(str)-slen);
676 /* Find end of list, deleting any existing instance */
678 left = lenof(cfg->ttymodes);
680 int t = strchr(p, '\t') - p;
681 if (t == strlen(ttymodes[ind]) &&
682 strncmp(p, ttymodes[ind], t) == 0) {
683 memmove(p, p+strlen(p)+1, left - (strlen(p)+1));
686 left -= strlen(p) + 1;
689 /* Append new entry */
691 strncpy(p, str, left - 2);
692 dlg_refresh(td->listbox, dlg);
695 } else if (ctrl == td->rembutton) {
696 char *p = cfg->ttymodes;
697 int i = 0, len = lenof(cfg->ttymodes);
699 if (dlg_listbox_issel(td->listbox, dlg, i)) {
700 memmove(p, p+strlen(p)+1, len - (strlen(p)+1));
704 len -= strlen(p) + 1;
708 memset(p, 0, lenof(cfg->ttymodes) - len);
709 dlg_refresh(td->listbox, dlg);
714 struct environ_data {
715 union control *varbox, *valbox, *addbutton, *rembutton, *listbox;
718 static void environ_handler(union control *ctrl, void *dlg,
719 void *data, int event)
721 Config *cfg = (Config *)data;
722 struct environ_data *ed =
723 (struct environ_data *)ctrl->generic.context.p;
725 if (event == EVENT_REFRESH) {
726 if (ctrl == ed->listbox) {
727 char *p = cfg->environmt;
728 dlg_update_start(ctrl, dlg);
729 dlg_listbox_clear(ctrl, dlg);
731 dlg_listbox_add(ctrl, dlg, p);
734 dlg_update_done(ctrl, dlg);
736 } else if (event == EVENT_ACTION) {
737 if (ctrl == ed->addbutton) {
738 char str[sizeof(cfg->environmt)];
740 dlg_editbox_get(ed->varbox, dlg, str, sizeof(str)-1);
745 p = str + strlen(str);
747 dlg_editbox_get(ed->valbox, dlg, p, sizeof(str)-1 - (p - str));
758 if ((p - cfg->environmt) + strlen(str) + 2 <
759 sizeof(cfg->environmt)) {
761 p[strlen(str) + 1] = '\0';
762 dlg_listbox_add(ed->listbox, dlg, str);
763 dlg_editbox_set(ed->varbox, dlg, "");
764 dlg_editbox_set(ed->valbox, dlg, "");
766 dlg_error_msg(dlg, "Environment too big");
768 } else if (ctrl == ed->rembutton) {
769 int i = dlg_listbox_index(ed->listbox, dlg);
775 dlg_listbox_del(ed->listbox, dlg, i);
803 struct portfwd_data {
804 union control *addbutton, *rembutton, *listbox;
805 union control *sourcebox, *destbox, *direction;
807 union control *addressfamily;
811 static void portfwd_handler(union control *ctrl, void *dlg,
812 void *data, int event)
814 Config *cfg = (Config *)data;
815 struct portfwd_data *pfd =
816 (struct portfwd_data *)ctrl->generic.context.p;
818 if (event == EVENT_REFRESH) {
819 if (ctrl == pfd->listbox) {
820 char *p = cfg->portfwd;
821 dlg_update_start(ctrl, dlg);
822 dlg_listbox_clear(ctrl, dlg);
824 dlg_listbox_add(ctrl, dlg, p);
827 dlg_update_done(ctrl, dlg);
828 } else if (ctrl == pfd->direction) {
832 dlg_radiobutton_set(ctrl, dlg, 0);
834 } else if (ctrl == pfd->addressfamily) {
835 dlg_radiobutton_set(ctrl, dlg, 0);
838 } else if (event == EVENT_ACTION) {
839 if (ctrl == pfd->addbutton) {
840 char str[sizeof(cfg->portfwd)];
847 whichbutton = dlg_radiobutton_get(pfd->addressfamily, dlg);
848 if (whichbutton == 1)
850 else if (whichbutton == 2)
854 whichbutton = dlg_radiobutton_get(pfd->direction, dlg);
855 if (whichbutton == 0)
857 else if (whichbutton == 1)
863 dlg_editbox_get(pfd->sourcebox, dlg, str+i, sizeof(str) - i);
865 dlg_error_msg(dlg, "You need to specify a source port number");
868 p = str + strlen(str);
871 dlg_editbox_get(pfd->destbox, dlg, p,
872 sizeof(str) - (p - str));
873 if (!*p || !strchr(p, ':')) {
875 "You need to specify a destination address\n"
876 "in the form \"host.name:port\"");
887 if ((p - cfg->portfwd) + strlen(str) + 2 <=
888 sizeof(cfg->portfwd)) {
890 p[strlen(str) + 1] = '\0';
891 dlg_listbox_add(pfd->listbox, dlg, str);
892 dlg_editbox_set(pfd->sourcebox, dlg, "");
893 dlg_editbox_set(pfd->destbox, dlg, "");
895 dlg_error_msg(dlg, "Too many forwardings");
897 } else if (ctrl == pfd->rembutton) {
898 int i = dlg_listbox_index(pfd->listbox, dlg);
904 dlg_listbox_del(pfd->listbox, dlg, i);
932 void setup_config_box(struct controlbox *b, int midsession,
933 int protocol, int protcfginfo)
935 struct controlset *s;
936 struct sessionsaver_data *ssd;
937 struct charclass_data *ccd;
938 struct colour_data *cd;
939 struct ttymodes_data *td;
940 struct environ_data *ed;
941 struct portfwd_data *pfd;
945 ssd = (struct sessionsaver_data *)
946 ctrl_alloc(b, sizeof(struct sessionsaver_data));
947 memset(ssd, 0, sizeof(*ssd));
948 ssd->midsession = midsession;
951 * The standard panel that appears at the bottom of all panels:
952 * Open, Cancel, Apply etc.
954 s = ctrl_getset(b, "", "", "");
955 ctrl_columns(s, 5, 20, 20, 20, 20, 20);
956 ssd->okbutton = ctrl_pushbutton(s,
957 (midsession ? "Apply" : "Open"),
958 (char)(midsession ? 'a' : 'o'),
960 sessionsaver_handler, P(ssd));
961 ssd->okbutton->button.isdefault = TRUE;
962 ssd->okbutton->generic.column = 3;
963 ssd->cancelbutton = ctrl_pushbutton(s, "Cancel", 'c', HELPCTX(no_help),
964 sessionsaver_handler, P(ssd));
965 ssd->cancelbutton->button.iscancel = TRUE;
966 ssd->cancelbutton->generic.column = 4;
967 /* We carefully don't close the 5-column part, so that platform-
968 * specific add-ons can put extra buttons alongside Open and Cancel. */
973 str = dupprintf("Basic options for your %s session", appname);
974 ctrl_settitle(b, "Session", str);
978 s = ctrl_getset(b, "Session", "hostport",
979 "Specify your connection by host name or IP address");
980 ctrl_columns(s, 2, 75, 25);
981 c = ctrl_editbox(s, "Host Name (or IP address)", 'n', 100,
982 HELPCTX(session_hostname),
983 dlg_stdeditbox_handler, I(offsetof(Config,host)),
984 I(sizeof(((Config *)0)->host)));
985 c->generic.column = 0;
986 c = ctrl_editbox(s, "Port", 'p', 100, HELPCTX(session_hostname),
987 dlg_stdeditbox_handler,
988 I(offsetof(Config,port)), I(-1));
989 c->generic.column = 1;
990 ctrl_columns(s, 1, 100);
991 if (backends[3].name == NULL) {
992 ctrl_radiobuttons(s, "Protocol:", NO_SHORTCUT, 3,
993 HELPCTX(session_hostname),
994 protocolbuttons_handler, P(c),
995 "Raw", 'r', I(PROT_RAW),
996 "Telnet", 't', I(PROT_TELNET),
997 "Rlogin", 'i', I(PROT_RLOGIN),
1000 ctrl_radiobuttons(s, "Protocol:", NO_SHORTCUT, 4,
1001 HELPCTX(session_hostname),
1002 protocolbuttons_handler, P(c),
1003 "Raw", 'r', I(PROT_RAW),
1004 "Telnet", 't', I(PROT_TELNET),
1005 "Rlogin", 'i', I(PROT_RLOGIN),
1006 "SSH", 's', I(PROT_SSH),
1012 * The Load/Save panel is available even in mid-session.
1014 s = ctrl_getset(b, "Session", "savedsessions",
1015 midsession ? "Save the current session settings" :
1016 "Load, save or delete a stored session");
1017 ctrl_columns(s, 2, 75, 25);
1018 get_sesslist(&ssd->sesslist, TRUE);
1019 ssd->editbox = ctrl_editbox(s, "Saved Sessions", 'e', 100,
1020 HELPCTX(session_saved),
1021 sessionsaver_handler, P(ssd), P(NULL));
1022 ssd->editbox->generic.column = 0;
1023 /* Reset columns so that the buttons are alongside the list, rather
1024 * than alongside that edit box. */
1025 ctrl_columns(s, 1, 100);
1026 ctrl_columns(s, 2, 75, 25);
1027 ssd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1028 HELPCTX(session_saved),
1029 sessionsaver_handler, P(ssd));
1030 ssd->listbox->generic.column = 0;
1031 ssd->listbox->listbox.height = 7;
1033 ssd->loadbutton = ctrl_pushbutton(s, "Load", 'l',
1034 HELPCTX(session_saved),
1035 sessionsaver_handler, P(ssd));
1036 ssd->loadbutton->generic.column = 1;
1038 /* We can't offer the Load button mid-session, as it would allow the
1039 * user to load and subsequently save settings they can't see. (And
1040 * also change otherwise immutable settings underfoot; that probably
1041 * shouldn't be a problem, but.) */
1042 ssd->loadbutton = NULL;
1044 /* "Save" button is permitted mid-session. */
1045 ssd->savebutton = ctrl_pushbutton(s, "Save", 'v',
1046 HELPCTX(session_saved),
1047 sessionsaver_handler, P(ssd));
1048 ssd->savebutton->generic.column = 1;
1050 ssd->delbutton = ctrl_pushbutton(s, "Delete", 'd',
1051 HELPCTX(session_saved),
1052 sessionsaver_handler, P(ssd));
1053 ssd->delbutton->generic.column = 1;
1055 /* Disable the Delete button mid-session too, for UI consistency. */
1056 ssd->delbutton = NULL;
1058 ctrl_columns(s, 1, 100);
1060 s = ctrl_getset(b, "Session", "otheropts", NULL);
1061 c = ctrl_radiobuttons(s, "Close window on exit:", 'w', 4,
1062 HELPCTX(session_coe),
1063 dlg_stdradiobutton_handler,
1064 I(offsetof(Config, close_on_exit)),
1065 "Always", I(FORCE_ON),
1066 "Never", I(FORCE_OFF),
1067 "Only on clean exit", I(AUTO), NULL);
1070 * The Session/Logging panel.
1072 ctrl_settitle(b, "Session/Logging", "Options controlling session logging");
1074 s = ctrl_getset(b, "Session/Logging", "main", NULL);
1076 * The logging buttons change depending on whether SSH packet
1077 * logging can sensibly be available.
1081 if ((midsession && protocol == PROT_SSH) ||
1082 (!midsession && backends[3].name != NULL))
1083 sshlogname = "Log SSH packet data";
1085 sshlogname = NULL; /* this will disable the button */
1086 ctrl_radiobuttons(s, "Session logging:", NO_SHORTCUT, 1,
1087 HELPCTX(logging_main),
1088 loggingbuttons_handler,
1089 I(offsetof(Config, logtype)),
1090 "Logging turned off completely", 't', I(LGTYP_NONE),
1091 "Log printable output only", 'p', I(LGTYP_ASCII),
1092 "Log all session output", 'l', I(LGTYP_DEBUG),
1093 sshlogname, 's', I(LGTYP_PACKETS),
1096 ctrl_filesel(s, "Log file name:", 'f',
1097 NULL, TRUE, "Select session log file name",
1098 HELPCTX(logging_filename),
1099 dlg_stdfilesel_handler, I(offsetof(Config, logfilename)));
1100 ctrl_text(s, "(Log file name can contain &Y, &M, &D for date,"
1101 " &T for time, and &H for host name)",
1102 HELPCTX(logging_filename));
1103 ctrl_radiobuttons(s, "What to do if the log file already exists:", 'e', 1,
1104 HELPCTX(logging_exists),
1105 dlg_stdradiobutton_handler, I(offsetof(Config,logxfovr)),
1106 "Always overwrite it", I(LGXF_OVR),
1107 "Always append to the end of it", I(LGXF_APN),
1108 "Ask the user every time", I(LGXF_ASK), NULL);
1109 ctrl_checkbox(s, "Flush log file frequently", 'u',
1110 HELPCTX(logging_flush),
1111 dlg_stdcheckbox_handler, I(offsetof(Config,logflush)));
1113 if ((midsession && protocol == PROT_SSH) ||
1114 (!midsession && backends[3].name != NULL)) {
1115 s = ctrl_getset(b, "Session/Logging", "ssh",
1116 "Options specific to SSH packet logging");
1117 ctrl_checkbox(s, "Omit known password fields", 'k',
1118 HELPCTX(logging_ssh_omit_password),
1119 dlg_stdcheckbox_handler, I(offsetof(Config,logomitpass)));
1120 ctrl_checkbox(s, "Omit session data", 'd',
1121 HELPCTX(logging_ssh_omit_data),
1122 dlg_stdcheckbox_handler, I(offsetof(Config,logomitdata)));
1126 * The Terminal panel.
1128 ctrl_settitle(b, "Terminal", "Options controlling the terminal emulation");
1130 s = ctrl_getset(b, "Terminal", "general", "Set various terminal options");
1131 ctrl_checkbox(s, "Auto wrap mode initially on", 'w',
1132 HELPCTX(terminal_autowrap),
1133 dlg_stdcheckbox_handler, I(offsetof(Config,wrap_mode)));
1134 ctrl_checkbox(s, "DEC Origin Mode initially on", 'd',
1135 HELPCTX(terminal_decom),
1136 dlg_stdcheckbox_handler, I(offsetof(Config,dec_om)));
1137 ctrl_checkbox(s, "Implicit CR in every LF", 'r',
1138 HELPCTX(terminal_lfhascr),
1139 dlg_stdcheckbox_handler, I(offsetof(Config,lfhascr)));
1140 ctrl_checkbox(s, "Use background colour to erase screen", 'e',
1141 HELPCTX(terminal_bce),
1142 dlg_stdcheckbox_handler, I(offsetof(Config,bce)));
1143 ctrl_checkbox(s, "Enable blinking text", 'n',
1144 HELPCTX(terminal_blink),
1145 dlg_stdcheckbox_handler, I(offsetof(Config,blinktext)));
1146 ctrl_editbox(s, "Answerback to ^E:", 's', 100,
1147 HELPCTX(terminal_answerback),
1148 dlg_stdeditbox_handler, I(offsetof(Config,answerback)),
1149 I(sizeof(((Config *)0)->answerback)));
1151 s = ctrl_getset(b, "Terminal", "ldisc", "Line discipline options");
1152 ctrl_radiobuttons(s, "Local echo:", 'l', 3,
1153 HELPCTX(terminal_localecho),
1154 dlg_stdradiobutton_handler,I(offsetof(Config,localecho)),
1156 "Force on", I(FORCE_ON),
1157 "Force off", I(FORCE_OFF), NULL);
1158 ctrl_radiobuttons(s, "Local line editing:", 't', 3,
1159 HELPCTX(terminal_localedit),
1160 dlg_stdradiobutton_handler,I(offsetof(Config,localedit)),
1162 "Force on", I(FORCE_ON),
1163 "Force off", I(FORCE_OFF), NULL);
1165 s = ctrl_getset(b, "Terminal", "printing", "Remote-controlled printing");
1166 ctrl_combobox(s, "Printer to send ANSI printer output to:", 'p', 100,
1167 HELPCTX(terminal_printing),
1168 printerbox_handler, P(NULL), P(NULL));
1171 * The Terminal/Keyboard panel.
1173 ctrl_settitle(b, "Terminal/Keyboard",
1174 "Options controlling the effects of keys");
1176 s = ctrl_getset(b, "Terminal/Keyboard", "mappings",
1177 "Change the sequences sent by:");
1178 ctrl_radiobuttons(s, "The Backspace key", 'b', 2,
1179 HELPCTX(keyboard_backspace),
1180 dlg_stdradiobutton_handler,
1181 I(offsetof(Config, bksp_is_delete)),
1182 "Control-H", I(0), "Control-? (127)", I(1), NULL);
1183 ctrl_radiobuttons(s, "The Home and End keys", 'e', 2,
1184 HELPCTX(keyboard_homeend),
1185 dlg_stdradiobutton_handler,
1186 I(offsetof(Config, rxvt_homeend)),
1187 "Standard", I(0), "rxvt", I(1), NULL);
1188 ctrl_radiobuttons(s, "The Function keys and keypad", 'f', 3,
1189 HELPCTX(keyboard_funkeys),
1190 dlg_stdradiobutton_handler,
1191 I(offsetof(Config, funky_type)),
1192 "ESC[n~", I(0), "Linux", I(1), "Xterm R6", I(2),
1193 "VT400", I(3), "VT100+", I(4), "SCO", I(5), NULL);
1195 s = ctrl_getset(b, "Terminal/Keyboard", "appkeypad",
1196 "Application keypad settings:");
1197 ctrl_radiobuttons(s, "Initial state of cursor keys:", 'r', 3,
1198 HELPCTX(keyboard_appcursor),
1199 dlg_stdradiobutton_handler,
1200 I(offsetof(Config, app_cursor)),
1201 "Normal", I(0), "Application", I(1), NULL);
1202 ctrl_radiobuttons(s, "Initial state of numeric keypad:", 'n', 3,
1203 HELPCTX(keyboard_appkeypad),
1204 numeric_keypad_handler, P(NULL),
1205 "Normal", I(0), "Application", I(1), "NetHack", I(2),
1209 * The Terminal/Bell panel.
1211 ctrl_settitle(b, "Terminal/Bell",
1212 "Options controlling the terminal bell");
1214 s = ctrl_getset(b, "Terminal/Bell", "style", "Set the style of bell");
1215 ctrl_radiobuttons(s, "Action to happen when a bell occurs:", 'b', 1,
1216 HELPCTX(bell_style),
1217 dlg_stdradiobutton_handler, I(offsetof(Config, beep)),
1218 "None (bell disabled)", I(BELL_DISABLED),
1219 "Make default system alert sound", I(BELL_DEFAULT),
1220 "Visual bell (flash window)", I(BELL_VISUAL), NULL);
1222 s = ctrl_getset(b, "Terminal/Bell", "overload",
1223 "Control the bell overload behaviour");
1224 ctrl_checkbox(s, "Bell is temporarily disabled when over-used", 'd',
1225 HELPCTX(bell_overload),
1226 dlg_stdcheckbox_handler, I(offsetof(Config,bellovl)));
1227 ctrl_editbox(s, "Over-use means this many bells...", 'm', 20,
1228 HELPCTX(bell_overload),
1229 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_n)), I(-1));
1230 ctrl_editbox(s, "... in this many seconds", 't', 20,
1231 HELPCTX(bell_overload),
1232 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_t)),
1234 ctrl_text(s, "The bell is re-enabled after a few seconds of silence.",
1235 HELPCTX(bell_overload));
1236 ctrl_editbox(s, "Seconds of silence required", 's', 20,
1237 HELPCTX(bell_overload),
1238 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_s)),
1242 * The Terminal/Features panel.
1244 ctrl_settitle(b, "Terminal/Features",
1245 "Enabling and disabling advanced terminal features");
1247 s = ctrl_getset(b, "Terminal/Features", "main", NULL);
1248 ctrl_checkbox(s, "Disable application cursor keys mode", 'u',
1249 HELPCTX(features_application),
1250 dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_c)));
1251 ctrl_checkbox(s, "Disable application keypad mode", 'k',
1252 HELPCTX(features_application),
1253 dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_k)));
1254 ctrl_checkbox(s, "Disable xterm-style mouse reporting", 'x',
1255 HELPCTX(features_mouse),
1256 dlg_stdcheckbox_handler, I(offsetof(Config,no_mouse_rep)));
1257 ctrl_checkbox(s, "Disable remote-controlled terminal resizing", 's',
1258 HELPCTX(features_resize),
1259 dlg_stdcheckbox_handler,
1260 I(offsetof(Config,no_remote_resize)));
1261 ctrl_checkbox(s, "Disable switching to alternate terminal screen", 'w',
1262 HELPCTX(features_altscreen),
1263 dlg_stdcheckbox_handler, I(offsetof(Config,no_alt_screen)));
1264 ctrl_checkbox(s, "Disable remote-controlled window title changing", 't',
1265 HELPCTX(features_retitle),
1266 dlg_stdcheckbox_handler,
1267 I(offsetof(Config,no_remote_wintitle)));
1268 ctrl_checkbox(s, "Disable remote window title querying (SECURITY)",
1269 'q', HELPCTX(features_qtitle), dlg_stdcheckbox_handler,
1270 I(offsetof(Config,no_remote_qtitle)));
1271 ctrl_checkbox(s, "Disable destructive backspace on server sending ^?",'b',
1272 HELPCTX(features_dbackspace),
1273 dlg_stdcheckbox_handler, I(offsetof(Config,no_dbackspace)));
1274 ctrl_checkbox(s, "Disable remote-controlled character set configuration",
1275 'r', HELPCTX(features_charset), dlg_stdcheckbox_handler,
1276 I(offsetof(Config,no_remote_charset)));
1277 ctrl_checkbox(s, "Disable Arabic text shaping",
1278 'l', HELPCTX(features_arabicshaping), dlg_stdcheckbox_handler,
1279 I(offsetof(Config, arabicshaping)));
1280 ctrl_checkbox(s, "Disable bidirectional text display",
1281 'd', HELPCTX(features_bidi), dlg_stdcheckbox_handler,
1282 I(offsetof(Config, bidi)));
1287 str = dupprintf("Options controlling %s's window", appname);
1288 ctrl_settitle(b, "Window", str);
1291 s = ctrl_getset(b, "Window", "size", "Set the size of the window");
1292 ctrl_columns(s, 2, 50, 50);
1293 c = ctrl_editbox(s, "Rows", 'r', 100,
1294 HELPCTX(window_size),
1295 dlg_stdeditbox_handler, I(offsetof(Config,height)),I(-1));
1296 c->generic.column = 0;
1297 c = ctrl_editbox(s, "Columns", 'm', 100,
1298 HELPCTX(window_size),
1299 dlg_stdeditbox_handler, I(offsetof(Config,width)), I(-1));
1300 c->generic.column = 1;
1301 ctrl_columns(s, 1, 100);
1303 s = ctrl_getset(b, "Window", "scrollback",
1304 "Control the scrollback in the window");
1305 ctrl_editbox(s, "Lines of scrollback", 's', 50,
1306 HELPCTX(window_scrollback),
1307 dlg_stdeditbox_handler, I(offsetof(Config,savelines)), I(-1));
1308 ctrl_checkbox(s, "Display scrollbar", 'd',
1309 HELPCTX(window_scrollback),
1310 dlg_stdcheckbox_handler, I(offsetof(Config,scrollbar)));
1311 ctrl_checkbox(s, "Reset scrollback on keypress", 'k',
1312 HELPCTX(window_scrollback),
1313 dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_key)));
1314 ctrl_checkbox(s, "Reset scrollback on display activity", 'p',
1315 HELPCTX(window_scrollback),
1316 dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_disp)));
1317 ctrl_checkbox(s, "Push erased text into scrollback", 'e',
1318 HELPCTX(window_erased),
1319 dlg_stdcheckbox_handler,
1320 I(offsetof(Config,erase_to_scrollback)));
1323 * The Window/Appearance panel.
1325 str = dupprintf("Configure the appearance of %s's window", appname);
1326 ctrl_settitle(b, "Window/Appearance", str);
1329 s = ctrl_getset(b, "Window/Appearance", "cursor",
1330 "Adjust the use of the cursor");
1331 ctrl_radiobuttons(s, "Cursor appearance:", NO_SHORTCUT, 3,
1332 HELPCTX(appearance_cursor),
1333 dlg_stdradiobutton_handler,
1334 I(offsetof(Config, cursor_type)),
1336 "Underline", 'u', I(1),
1337 "Vertical line", 'v', I(2), NULL);
1338 ctrl_checkbox(s, "Cursor blinks", 'b',
1339 HELPCTX(appearance_cursor),
1340 dlg_stdcheckbox_handler, I(offsetof(Config,blink_cur)));
1342 s = ctrl_getset(b, "Window/Appearance", "font",
1344 ctrl_fontsel(s, "Font used in the terminal window", 'n',
1345 HELPCTX(appearance_font),
1346 dlg_stdfontsel_handler, I(offsetof(Config, font)));
1348 s = ctrl_getset(b, "Window/Appearance", "mouse",
1349 "Adjust the use of the mouse pointer");
1350 ctrl_checkbox(s, "Hide mouse pointer when typing in window", 'p',
1351 HELPCTX(appearance_hidemouse),
1352 dlg_stdcheckbox_handler, I(offsetof(Config,hide_mouseptr)));
1354 s = ctrl_getset(b, "Window/Appearance", "border",
1355 "Adjust the window border");
1356 ctrl_editbox(s, "Gap between text and window edge:", 'e', 20,
1357 HELPCTX(appearance_border),
1358 dlg_stdeditbox_handler,
1359 I(offsetof(Config,window_border)), I(-1));
1362 * The Window/Behaviour panel.
1364 str = dupprintf("Configure the behaviour of %s's window", appname);
1365 ctrl_settitle(b, "Window/Behaviour", str);
1368 s = ctrl_getset(b, "Window/Behaviour", "title",
1369 "Adjust the behaviour of the window title");
1370 ctrl_editbox(s, "Window title:", 't', 100,
1371 HELPCTX(appearance_title),
1372 dlg_stdeditbox_handler, I(offsetof(Config,wintitle)),
1373 I(sizeof(((Config *)0)->wintitle)));
1374 ctrl_checkbox(s, "Separate window and icon titles", 'i',
1375 HELPCTX(appearance_title),
1376 dlg_stdcheckbox_handler,
1377 I(CHECKBOX_INVERT | offsetof(Config,win_name_always)));
1379 s = ctrl_getset(b, "Window/Behaviour", "main", NULL);
1380 ctrl_checkbox(s, "Warn before closing window", 'w',
1381 HELPCTX(behaviour_closewarn),
1382 dlg_stdcheckbox_handler, I(offsetof(Config,warn_on_close)));
1385 * The Window/Translation panel.
1387 ctrl_settitle(b, "Window/Translation",
1388 "Options controlling character set translation");
1390 s = ctrl_getset(b, "Window/Translation", "trans",
1391 "Character set translation on received data");
1392 ctrl_combobox(s, "Received data assumed to be in which character set:",
1393 'r', 100, HELPCTX(translation_codepage),
1394 codepage_handler, P(NULL), P(NULL));
1396 s = ctrl_getset(b, "Window/Translation", "tweaks", NULL);
1397 ctrl_checkbox(s, "Treat CJK ambiguous characters as wide", 'w',
1398 HELPCTX(translation_cjk_ambig_wide),
1399 dlg_stdcheckbox_handler, I(offsetof(Config,cjk_ambig_wide)));
1401 str = dupprintf("Adjust how %s handles line drawing characters", appname);
1402 s = ctrl_getset(b, "Window/Translation", "linedraw", str);
1404 ctrl_radiobuttons(s, "Handling of line drawing characters:", NO_SHORTCUT,1,
1405 HELPCTX(translation_linedraw),
1406 dlg_stdradiobutton_handler,
1407 I(offsetof(Config, vtmode)),
1408 "Use Unicode line drawing code points",'u',I(VT_UNICODE),
1409 "Poor man's line drawing (+, - and |)",'p',I(VT_POORMAN),
1411 ctrl_checkbox(s, "Copy and paste line drawing characters as lqqqk",'d',
1412 HELPCTX(selection_linedraw),
1413 dlg_stdcheckbox_handler, I(offsetof(Config,rawcnp)));
1416 * The Window/Selection panel.
1418 ctrl_settitle(b, "Window/Selection", "Options controlling copy and paste");
1420 s = ctrl_getset(b, "Window/Selection", "mouse",
1421 "Control use of mouse");
1422 ctrl_checkbox(s, "Shift overrides application's use of mouse", 'p',
1423 HELPCTX(selection_shiftdrag),
1424 dlg_stdcheckbox_handler, I(offsetof(Config,mouse_override)));
1425 ctrl_radiobuttons(s,
1426 "Default selection mode (Alt+drag does the other one):",
1428 HELPCTX(selection_rect),
1429 dlg_stdradiobutton_handler,
1430 I(offsetof(Config, rect_select)),
1431 "Normal", 'n', I(0),
1432 "Rectangular block", 'r', I(1), NULL);
1434 s = ctrl_getset(b, "Window/Selection", "charclass",
1435 "Control the select-one-word-at-a-time mode");
1436 ccd = (struct charclass_data *)
1437 ctrl_alloc(b, sizeof(struct charclass_data));
1438 ccd->listbox = ctrl_listbox(s, "Character classes:", 'e',
1439 HELPCTX(selection_charclasses),
1440 charclass_handler, P(ccd));
1441 ccd->listbox->listbox.multisel = 1;
1442 ccd->listbox->listbox.ncols = 4;
1443 ccd->listbox->listbox.percentages = snewn(4, int);
1444 ccd->listbox->listbox.percentages[0] = 15;
1445 ccd->listbox->listbox.percentages[1] = 25;
1446 ccd->listbox->listbox.percentages[2] = 20;
1447 ccd->listbox->listbox.percentages[3] = 40;
1448 ctrl_columns(s, 2, 67, 33);
1449 ccd->editbox = ctrl_editbox(s, "Set to class", 't', 50,
1450 HELPCTX(selection_charclasses),
1451 charclass_handler, P(ccd), P(NULL));
1452 ccd->editbox->generic.column = 0;
1453 ccd->button = ctrl_pushbutton(s, "Set", 's',
1454 HELPCTX(selection_charclasses),
1455 charclass_handler, P(ccd));
1456 ccd->button->generic.column = 1;
1457 ctrl_columns(s, 1, 100);
1460 * The Window/Colours panel.
1462 ctrl_settitle(b, "Window/Colours", "Options controlling use of colours");
1464 s = ctrl_getset(b, "Window/Colours", "general",
1465 "General options for colour usage");
1466 ctrl_checkbox(s, "Allow terminal to specify ANSI colours", 'i',
1467 HELPCTX(colours_ansi),
1468 dlg_stdcheckbox_handler, I(offsetof(Config,ansi_colour)));
1469 ctrl_checkbox(s, "Allow terminal to use xterm 256-colour mode", '2',
1470 HELPCTX(colours_xterm256), dlg_stdcheckbox_handler,
1471 I(offsetof(Config,xterm_256_colour)));
1472 ctrl_checkbox(s, "Bolded text is a different colour", 'b',
1473 HELPCTX(colours_bold),
1474 dlg_stdcheckbox_handler, I(offsetof(Config,bold_colour)));
1476 str = dupprintf("Adjust the precise colours %s displays", appname);
1477 s = ctrl_getset(b, "Window/Colours", "adjust", str);
1479 ctrl_text(s, "Select a colour from the list, and then click the"
1480 " Modify button to change its appearance.",
1481 HELPCTX(colours_config));
1482 ctrl_columns(s, 2, 67, 33);
1483 cd = (struct colour_data *)ctrl_alloc(b, sizeof(struct colour_data));
1484 cd->listbox = ctrl_listbox(s, "Select a colour to adjust:", 'u',
1485 HELPCTX(colours_config), colour_handler, P(cd));
1486 cd->listbox->generic.column = 0;
1487 cd->listbox->listbox.height = 7;
1488 c = ctrl_text(s, "RGB value:", HELPCTX(colours_config));
1489 c->generic.column = 1;
1490 cd->redit = ctrl_editbox(s, "Red", 'r', 50, HELPCTX(colours_config),
1491 colour_handler, P(cd), P(NULL));
1492 cd->redit->generic.column = 1;
1493 cd->gedit = ctrl_editbox(s, "Green", 'n', 50, HELPCTX(colours_config),
1494 colour_handler, P(cd), P(NULL));
1495 cd->gedit->generic.column = 1;
1496 cd->bedit = ctrl_editbox(s, "Blue", 'e', 50, HELPCTX(colours_config),
1497 colour_handler, P(cd), P(NULL));
1498 cd->bedit->generic.column = 1;
1499 cd->button = ctrl_pushbutton(s, "Modify", 'm', HELPCTX(colours_config),
1500 colour_handler, P(cd));
1501 cd->button->generic.column = 1;
1502 ctrl_columns(s, 1, 100);
1505 * The Connection panel. This doesn't show up if we're in a
1506 * non-network utility such as pterm. We tell this by being
1507 * passed a protocol < 0.
1509 if (protocol >= 0) {
1510 ctrl_settitle(b, "Connection", "Options controlling the connection");
1512 s = ctrl_getset(b, "Connection", "keepalive",
1513 "Sending of null packets to keep session active");
1514 ctrl_editbox(s, "Seconds between keepalives (0 to turn off)", 'k', 20,
1515 HELPCTX(connection_keepalive),
1516 dlg_stdeditbox_handler, I(offsetof(Config,ping_interval)),
1520 s = ctrl_getset(b, "Connection", "tcp",
1521 "Low-level TCP connection options");
1522 ctrl_checkbox(s, "Disable Nagle's algorithm (TCP_NODELAY option)",
1523 'n', HELPCTX(connection_nodelay),
1524 dlg_stdcheckbox_handler,
1525 I(offsetof(Config,tcp_nodelay)));
1526 ctrl_checkbox(s, "Enable TCP keepalives (SO_KEEPALIVE option)",
1527 'p', HELPCTX(connection_tcpkeepalive),
1528 dlg_stdcheckbox_handler,
1529 I(offsetof(Config,tcp_keepalives)));
1531 s = ctrl_getset(b, "Connection", "ipversion",
1532 "Internet protocol version");
1533 ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
1534 HELPCTX(connection_ipversion),
1535 dlg_stdradiobutton_handler,
1536 I(offsetof(Config, addressfamily)),
1537 "Auto", 'u', I(ADDRTYPE_UNSPEC),
1538 "IPv4", '4', I(ADDRTYPE_IPV4),
1539 "IPv6", '6', I(ADDRTYPE_IPV6),
1545 * A sub-panel Connection/Data, containing options that
1546 * decide on data to send to the server.
1549 ctrl_settitle(b, "Connection/Data", "Data to send to the server");
1551 s = ctrl_getset(b, "Connection/Data", "login",
1553 ctrl_editbox(s, "Auto-login username", 'u', 50,
1554 HELPCTX(connection_username),
1555 dlg_stdeditbox_handler, I(offsetof(Config,username)),
1556 I(sizeof(((Config *)0)->username)));
1558 s = ctrl_getset(b, "Connection/Data", "term",
1559 "Terminal details");
1560 ctrl_editbox(s, "Terminal-type string", 't', 50,
1561 HELPCTX(connection_termtype),
1562 dlg_stdeditbox_handler, I(offsetof(Config,termtype)),
1563 I(sizeof(((Config *)0)->termtype)));
1564 ctrl_editbox(s, "Terminal speeds", 's', 50,
1565 HELPCTX(connection_termspeed),
1566 dlg_stdeditbox_handler, I(offsetof(Config,termspeed)),
1567 I(sizeof(((Config *)0)->termspeed)));
1569 s = ctrl_getset(b, "Connection/Data", "env",
1570 "Environment variables");
1571 ctrl_columns(s, 2, 80, 20);
1572 ed = (struct environ_data *)
1573 ctrl_alloc(b, sizeof(struct environ_data));
1574 ed->varbox = ctrl_editbox(s, "Variable", 'v', 60,
1575 HELPCTX(telnet_environ),
1576 environ_handler, P(ed), P(NULL));
1577 ed->varbox->generic.column = 0;
1578 ed->valbox = ctrl_editbox(s, "Value", 'l', 60,
1579 HELPCTX(telnet_environ),
1580 environ_handler, P(ed), P(NULL));
1581 ed->valbox->generic.column = 0;
1582 ed->addbutton = ctrl_pushbutton(s, "Add", 'd',
1583 HELPCTX(telnet_environ),
1584 environ_handler, P(ed));
1585 ed->addbutton->generic.column = 1;
1586 ed->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1587 HELPCTX(telnet_environ),
1588 environ_handler, P(ed));
1589 ed->rembutton->generic.column = 1;
1590 ctrl_columns(s, 1, 100);
1591 ed->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1592 HELPCTX(telnet_environ),
1593 environ_handler, P(ed));
1594 ed->listbox->listbox.height = 3;
1595 ed->listbox->listbox.ncols = 2;
1596 ed->listbox->listbox.percentages = snewn(2, int);
1597 ed->listbox->listbox.percentages[0] = 30;
1598 ed->listbox->listbox.percentages[1] = 70;
1605 * The Connection/Proxy panel.
1607 ctrl_settitle(b, "Connection/Proxy",
1608 "Options controlling proxy usage");
1610 s = ctrl_getset(b, "Connection/Proxy", "basics", NULL);
1611 ctrl_radiobuttons(s, "Proxy type:", 't', 3,
1612 HELPCTX(proxy_type),
1613 dlg_stdradiobutton_handler,
1614 I(offsetof(Config, proxy_type)),
1615 "None", I(PROXY_NONE),
1616 "SOCKS 4", I(PROXY_SOCKS4),
1617 "SOCKS 5", I(PROXY_SOCKS5),
1618 "HTTP", I(PROXY_HTTP),
1619 "Telnet", I(PROXY_TELNET),
1621 ctrl_columns(s, 2, 80, 20);
1622 c = ctrl_editbox(s, "Proxy hostname", 'y', 100,
1623 HELPCTX(proxy_main),
1624 dlg_stdeditbox_handler,
1625 I(offsetof(Config,proxy_host)),
1626 I(sizeof(((Config *)0)->proxy_host)));
1627 c->generic.column = 0;
1628 c = ctrl_editbox(s, "Port", 'p', 100,
1629 HELPCTX(proxy_main),
1630 dlg_stdeditbox_handler,
1631 I(offsetof(Config,proxy_port)),
1633 c->generic.column = 1;
1634 ctrl_columns(s, 1, 100);
1635 ctrl_editbox(s, "Exclude Hosts/IPs", 'e', 100,
1636 HELPCTX(proxy_exclude),
1637 dlg_stdeditbox_handler,
1638 I(offsetof(Config,proxy_exclude_list)),
1639 I(sizeof(((Config *)0)->proxy_exclude_list)));
1640 ctrl_checkbox(s, "Consider proxying local host connections", 'x',
1641 HELPCTX(proxy_exclude),
1642 dlg_stdcheckbox_handler,
1643 I(offsetof(Config,even_proxy_localhost)));
1644 ctrl_radiobuttons(s, "Do DNS name lookup at proxy end:", 'd', 3,
1646 dlg_stdradiobutton_handler,
1647 I(offsetof(Config, proxy_dns)),
1650 "Yes", I(FORCE_ON), NULL);
1651 ctrl_editbox(s, "Username", 'u', 60,
1652 HELPCTX(proxy_auth),
1653 dlg_stdeditbox_handler,
1654 I(offsetof(Config,proxy_username)),
1655 I(sizeof(((Config *)0)->proxy_username)));
1656 c = ctrl_editbox(s, "Password", 'w', 60,
1657 HELPCTX(proxy_auth),
1658 dlg_stdeditbox_handler,
1659 I(offsetof(Config,proxy_password)),
1660 I(sizeof(((Config *)0)->proxy_password)));
1661 c->editbox.password = 1;
1662 ctrl_editbox(s, "Telnet command", 'm', 100,
1663 HELPCTX(proxy_command),
1664 dlg_stdeditbox_handler,
1665 I(offsetof(Config,proxy_telnet_command)),
1666 I(sizeof(((Config *)0)->proxy_telnet_command)));
1670 * The Telnet panel exists in the base config box, and in a
1671 * mid-session reconfig box _if_ we're using Telnet.
1673 if (!midsession || protocol == PROT_TELNET) {
1675 * The Connection/Telnet panel.
1677 ctrl_settitle(b, "Connection/Telnet",
1678 "Options controlling Telnet connections");
1680 s = ctrl_getset(b, "Connection/Telnet", "protocol",
1681 "Telnet protocol adjustments");
1684 ctrl_radiobuttons(s, "Handling of OLD_ENVIRON ambiguity:",
1686 HELPCTX(telnet_oldenviron),
1687 dlg_stdradiobutton_handler,
1688 I(offsetof(Config, rfc_environ)),
1689 "BSD (commonplace)", 'b', I(0),
1690 "RFC 1408 (unusual)", 'f', I(1), NULL);
1691 ctrl_radiobuttons(s, "Telnet negotiation mode:", 't', 2,
1692 HELPCTX(telnet_passive),
1693 dlg_stdradiobutton_handler,
1694 I(offsetof(Config, passive_telnet)),
1695 "Passive", I(1), "Active", I(0), NULL);
1697 ctrl_checkbox(s, "Keyboard sends Telnet special commands", 'k',
1698 HELPCTX(telnet_specialkeys),
1699 dlg_stdcheckbox_handler,
1700 I(offsetof(Config,telnet_keyboard)));
1701 ctrl_checkbox(s, "Return key sends Telnet New Line instead of ^M",
1702 'm', HELPCTX(telnet_newline),
1703 dlg_stdcheckbox_handler,
1704 I(offsetof(Config,telnet_newline)));
1710 * The Connection/Rlogin panel.
1712 ctrl_settitle(b, "Connection/Rlogin",
1713 "Options controlling Rlogin connections");
1715 s = ctrl_getset(b, "Connection/Rlogin", "data",
1716 "Data to send to the server");
1717 ctrl_editbox(s, "Local username:", 'l', 50,
1718 HELPCTX(rlogin_localuser),
1719 dlg_stdeditbox_handler, I(offsetof(Config,localusername)),
1720 I(sizeof(((Config *)0)->localusername)));
1725 * All the SSH stuff is omitted in PuTTYtel, or in a reconfig
1726 * when we're not doing SSH.
1729 if (backends[3].name != NULL && (!midsession || protocol == PROT_SSH)) {
1732 * The Connection/SSH panel.
1734 ctrl_settitle(b, "Connection/SSH",
1735 "Options controlling SSH connections");
1737 if (midsession && protcfginfo == 1) {
1738 s = ctrl_getset(b, "Connection/SSH", "disclaimer", NULL);
1739 ctrl_text(s, "Nothing on this panel may be reconfigured in mid-"
1740 "session; it is only here so that sub-panels of it can "
1741 "exist without looking strange.", HELPCTX(no_help));
1746 s = ctrl_getset(b, "Connection/SSH", "data",
1747 "Data to send to the server");
1748 ctrl_editbox(s, "Remote command:", 'r', 100,
1749 HELPCTX(ssh_command),
1750 dlg_stdeditbox_handler, I(offsetof(Config,remote_cmd)),
1751 I(sizeof(((Config *)0)->remote_cmd)));
1753 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1754 ctrl_checkbox(s, "Don't start a shell or command at all", 'n',
1755 HELPCTX(ssh_noshell),
1756 dlg_stdcheckbox_handler,
1757 I(offsetof(Config,ssh_no_shell)));
1760 if (!midsession || protcfginfo != 1) {
1761 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1763 ctrl_checkbox(s, "Enable compression", 'e',
1764 HELPCTX(ssh_compress),
1765 dlg_stdcheckbox_handler,
1766 I(offsetof(Config,compression)));
1770 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1772 ctrl_radiobuttons(s, "Preferred SSH protocol version:", NO_SHORTCUT, 4,
1773 HELPCTX(ssh_protocol),
1774 dlg_stdradiobutton_handler,
1775 I(offsetof(Config, sshprot)),
1776 "1 only", 'l', I(0),
1779 "2 only", 'y', I(3), NULL);
1782 if (!midsession || protcfginfo != 1) {
1783 s = ctrl_getset(b, "Connection/SSH", "encryption", "Encryption options");
1784 c = ctrl_draglist(s, "Encryption cipher selection policy:", 's',
1785 HELPCTX(ssh_ciphers),
1786 cipherlist_handler, P(NULL));
1787 c->listbox.height = 6;
1789 ctrl_checkbox(s, "Enable legacy use of single-DES in SSH-2", 'i',
1790 HELPCTX(ssh_ciphers),
1791 dlg_stdcheckbox_handler,
1792 I(offsetof(Config,ssh2_des_cbc)));
1796 * The Connection/SSH/Kex panel. (Owing to repeat key
1797 * exchange, this is all meaningful in mid-session _if_
1798 * we're using SSH-2 or haven't decided yet.)
1800 if (protcfginfo != 1) {
1801 ctrl_settitle(b, "Connection/SSH/Kex",
1802 "Options controlling SSH key exchange");
1804 s = ctrl_getset(b, "Connection/SSH/Kex", "main",
1805 "Key exchange algorithm options");
1806 c = ctrl_draglist(s, "Algorithm selection policy:", 's',
1807 HELPCTX(ssh_kexlist),
1808 kexlist_handler, P(NULL));
1809 c->listbox.height = 5;
1811 s = ctrl_getset(b, "Connection/SSH/Kex", "repeat",
1812 "Options controlling key re-exchange");
1814 ctrl_editbox(s, "Max minutes before rekey (0 for no limit)", 't', 20,
1815 HELPCTX(ssh_kex_repeat),
1816 dlg_stdeditbox_handler,
1817 I(offsetof(Config,ssh_rekey_time)),
1819 ctrl_editbox(s, "Max data before rekey (0 for no limit)", 'x', 20,
1820 HELPCTX(ssh_kex_repeat),
1821 dlg_stdeditbox_handler,
1822 I(offsetof(Config,ssh_rekey_data)),
1824 ctrl_text(s, "(Use 1M for 1 megabyte, 1G for 1 gigabyte etc)",
1825 HELPCTX(ssh_kex_repeat));
1831 * The Connection/SSH/Auth panel.
1833 ctrl_settitle(b, "Connection/SSH/Auth",
1834 "Options controlling SSH authentication");
1836 s = ctrl_getset(b, "Connection/SSH/Auth", "main", NULL);
1837 ctrl_checkbox(s, "Bypass authentication entirely (SSH-2 only)", 'b',
1838 HELPCTX(ssh_auth_bypass),
1839 dlg_stdcheckbox_handler,
1840 I(offsetof(Config,ssh_no_userauth)));
1842 s = ctrl_getset(b, "Connection/SSH/Auth", "methods",
1843 "Authentication methods");
1844 ctrl_checkbox(s, "Attempt authentication using Pageant", 'p',
1845 HELPCTX(ssh_auth_pageant),
1846 dlg_stdcheckbox_handler,
1847 I(offsetof(Config,tryagent)));
1848 ctrl_checkbox(s, "Attempt TIS or CryptoCard auth (SSH-1)", 'm',
1849 HELPCTX(ssh_auth_tis),
1850 dlg_stdcheckbox_handler,
1851 I(offsetof(Config,try_tis_auth)));
1852 ctrl_checkbox(s, "Attempt \"keyboard-interactive\" auth (SSH-2)",
1853 'i', HELPCTX(ssh_auth_ki),
1854 dlg_stdcheckbox_handler,
1855 I(offsetof(Config,try_ki_auth)));
1857 s = ctrl_getset(b, "Connection/SSH/Auth", "params",
1858 "Authentication parameters");
1859 ctrl_checkbox(s, "Allow agent forwarding", 'f',
1860 HELPCTX(ssh_auth_agentfwd),
1861 dlg_stdcheckbox_handler, I(offsetof(Config,agentfwd)));
1862 ctrl_checkbox(s, "Allow attempted changes of username in SSH-2", 'u',
1863 HELPCTX(ssh_auth_changeuser),
1864 dlg_stdcheckbox_handler,
1865 I(offsetof(Config,change_username)));
1866 ctrl_filesel(s, "Private key file for authentication:", 'k',
1867 FILTER_KEY_FILES, FALSE, "Select private key file",
1868 HELPCTX(ssh_auth_privkey),
1869 dlg_stdfilesel_handler, I(offsetof(Config, keyfile)));
1874 * The Connection/SSH/TTY panel.
1876 ctrl_settitle(b, "Connection/SSH/TTY", "Remote terminal settings");
1878 s = ctrl_getset(b, "Connection/SSH/TTY", "sshtty", NULL);
1879 ctrl_checkbox(s, "Don't allocate a pseudo-terminal", 'p',
1881 dlg_stdcheckbox_handler,
1882 I(offsetof(Config,nopty)));
1884 s = ctrl_getset(b, "Connection/SSH/TTY", "ttymodes",
1886 td = (struct ttymodes_data *)
1887 ctrl_alloc(b, sizeof(struct ttymodes_data));
1888 ctrl_columns(s, 2, 75, 25);
1889 c = ctrl_text(s, "Terminal modes to send:", HELPCTX(ssh_ttymodes));
1890 c->generic.column = 0;
1891 td->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1892 HELPCTX(ssh_ttymodes),
1893 ttymodes_handler, P(td));
1894 td->rembutton->generic.column = 1;
1895 td->rembutton->generic.tabdelay = 1;
1896 ctrl_columns(s, 1, 100);
1897 td->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1898 HELPCTX(ssh_ttymodes),
1899 ttymodes_handler, P(td));
1900 td->listbox->listbox.multisel = 1;
1901 td->listbox->listbox.height = 4;
1902 td->listbox->listbox.ncols = 2;
1903 td->listbox->listbox.percentages = snewn(2, int);
1904 td->listbox->listbox.percentages[0] = 40;
1905 td->listbox->listbox.percentages[1] = 60;
1906 ctrl_tabdelay(s, td->rembutton);
1907 ctrl_columns(s, 2, 75, 25);
1908 td->modelist = ctrl_droplist(s, "Mode:", 'm', 67,
1909 HELPCTX(ssh_ttymodes),
1910 ttymodes_handler, P(td));
1911 td->modelist->generic.column = 0;
1912 td->addbutton = ctrl_pushbutton(s, "Add", 'd',
1913 HELPCTX(ssh_ttymodes),
1914 ttymodes_handler, P(td));
1915 td->addbutton->generic.column = 1;
1916 td->addbutton->generic.tabdelay = 1;
1917 ctrl_columns(s, 1, 100); /* column break */
1918 /* Bit of a hack to get the value radio buttons and
1919 * edit-box on the same row. */
1920 ctrl_columns(s, 3, 25, 50, 25);
1921 c = ctrl_text(s, "Value:", HELPCTX(ssh_ttymodes));
1922 c->generic.column = 0;
1923 td->valradio = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 2,
1924 HELPCTX(ssh_ttymodes),
1925 ttymodes_handler, P(td),
1926 "Auto", NO_SHORTCUT, P(NULL),
1927 "This:", NO_SHORTCUT, P(NULL),
1929 td->valradio->generic.column = 1;
1930 td->valbox = ctrl_editbox(s, NULL, NO_SHORTCUT, 100,
1931 HELPCTX(ssh_ttymodes),
1932 ttymodes_handler, P(td), P(NULL));
1933 td->valbox->generic.column = 2;
1934 ctrl_tabdelay(s, td->addbutton);
1940 * The Connection/SSH/X11 panel.
1942 ctrl_settitle(b, "Connection/SSH/X11",
1943 "Options controlling SSH X11 forwarding");
1945 s = ctrl_getset(b, "Connection/SSH/X11", "x11", "X11 forwarding");
1946 ctrl_checkbox(s, "Enable X11 forwarding", 'e',
1947 HELPCTX(ssh_tunnels_x11),
1948 dlg_stdcheckbox_handler,I(offsetof(Config,x11_forward)));
1949 ctrl_editbox(s, "X display location", 'x', 50,
1950 HELPCTX(ssh_tunnels_x11),
1951 dlg_stdeditbox_handler, I(offsetof(Config,x11_display)),
1952 I(sizeof(((Config *)0)->x11_display)));
1953 ctrl_radiobuttons(s, "Remote X11 authentication protocol", 'u', 2,
1954 HELPCTX(ssh_tunnels_x11auth),
1955 dlg_stdradiobutton_handler,
1956 I(offsetof(Config, x11_auth)),
1957 "MIT-Magic-Cookie-1", I(X11_MIT),
1958 "XDM-Authorization-1", I(X11_XDM), NULL);
1962 * The Tunnels panel _is_ still available in mid-session.
1964 ctrl_settitle(b, "Connection/SSH/Tunnels",
1965 "Options controlling SSH port forwarding");
1967 s = ctrl_getset(b, "Connection/SSH/Tunnels", "portfwd",
1969 ctrl_checkbox(s, "Local ports accept connections from other hosts",'t',
1970 HELPCTX(ssh_tunnels_portfwd_localhost),
1971 dlg_stdcheckbox_handler,
1972 I(offsetof(Config,lport_acceptall)));
1973 ctrl_checkbox(s, "Remote ports do the same (SSH-2 only)", 'p',
1974 HELPCTX(ssh_tunnels_portfwd_localhost),
1975 dlg_stdcheckbox_handler,
1976 I(offsetof(Config,rport_acceptall)));
1978 ctrl_columns(s, 3, 55, 20, 25);
1979 c = ctrl_text(s, "Forwarded ports:", HELPCTX(ssh_tunnels_portfwd));
1980 c->generic.column = COLUMN_FIELD(0,2);
1981 /* You want to select from the list, _then_ hit Remove. So tab order
1982 * should be that way round. */
1983 pfd = (struct portfwd_data *)ctrl_alloc(b,sizeof(struct portfwd_data));
1984 pfd->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1985 HELPCTX(ssh_tunnels_portfwd),
1986 portfwd_handler, P(pfd));
1987 pfd->rembutton->generic.column = 2;
1988 pfd->rembutton->generic.tabdelay = 1;
1989 pfd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1990 HELPCTX(ssh_tunnels_portfwd),
1991 portfwd_handler, P(pfd));
1992 pfd->listbox->listbox.height = 3;
1993 pfd->listbox->listbox.ncols = 2;
1994 pfd->listbox->listbox.percentages = snewn(2, int);
1995 pfd->listbox->listbox.percentages[0] = 20;
1996 pfd->listbox->listbox.percentages[1] = 80;
1997 ctrl_tabdelay(s, pfd->rembutton);
1998 ctrl_text(s, "Add new forwarded port:", HELPCTX(ssh_tunnels_portfwd));
1999 /* You want to enter source, destination and type, _then_ hit Add.
2000 * Again, we adjust the tab order to reflect this. */
2001 pfd->addbutton = ctrl_pushbutton(s, "Add", 'd',
2002 HELPCTX(ssh_tunnels_portfwd),
2003 portfwd_handler, P(pfd));
2004 pfd->addbutton->generic.column = 2;
2005 pfd->addbutton->generic.tabdelay = 1;
2006 pfd->sourcebox = ctrl_editbox(s, "Source port", 's', 40,
2007 HELPCTX(ssh_tunnels_portfwd),
2008 portfwd_handler, P(pfd), P(NULL));
2009 pfd->sourcebox->generic.column = 0;
2010 pfd->destbox = ctrl_editbox(s, "Destination", 'i', 67,
2011 HELPCTX(ssh_tunnels_portfwd),
2012 portfwd_handler, P(pfd), P(NULL));
2013 pfd->direction = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
2014 HELPCTX(ssh_tunnels_portfwd),
2015 portfwd_handler, P(pfd),
2016 "Local", 'l', P(NULL),
2017 "Remote", 'm', P(NULL),
2018 "Dynamic", 'y', P(NULL),
2021 pfd->addressfamily =
2022 ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
2023 HELPCTX(ssh_tunnels_portfwd_ipversion),
2024 portfwd_handler, P(pfd),
2025 "Auto", 'u', I(ADDRTYPE_UNSPEC),
2026 "IPv4", '4', I(ADDRTYPE_IPV4),
2027 "IPv6", '6', I(ADDRTYPE_IPV6),
2030 ctrl_tabdelay(s, pfd->addbutton);
2031 ctrl_columns(s, 1, 100);
2035 * The Connection/SSH/Bugs panel.
2037 ctrl_settitle(b, "Connection/SSH/Bugs",
2038 "Workarounds for SSH server bugs");
2040 s = ctrl_getset(b, "Connection/SSH/Bugs", "main",
2041 "Detection of known bugs in SSH servers");
2042 ctrl_droplist(s, "Chokes on SSH-1 ignore messages", 'i', 20,
2043 HELPCTX(ssh_bugs_ignore1),
2044 sshbug_handler, I(offsetof(Config,sshbug_ignore1)));
2045 ctrl_droplist(s, "Refuses all SSH-1 password camouflage", 's', 20,
2046 HELPCTX(ssh_bugs_plainpw1),
2047 sshbug_handler, I(offsetof(Config,sshbug_plainpw1)));
2048 ctrl_droplist(s, "Chokes on SSH-1 RSA authentication", 'r', 20,
2049 HELPCTX(ssh_bugs_rsa1),
2050 sshbug_handler, I(offsetof(Config,sshbug_rsa1)));
2051 ctrl_droplist(s, "Miscomputes SSH-2 HMAC keys", 'm', 20,
2052 HELPCTX(ssh_bugs_hmac2),
2053 sshbug_handler, I(offsetof(Config,sshbug_hmac2)));
2054 ctrl_droplist(s, "Miscomputes SSH-2 encryption keys", 'e', 20,
2055 HELPCTX(ssh_bugs_derivekey2),
2056 sshbug_handler, I(offsetof(Config,sshbug_derivekey2)));
2057 ctrl_droplist(s, "Requires padding on SSH-2 RSA signatures", 'p', 20,
2058 HELPCTX(ssh_bugs_rsapad2),
2059 sshbug_handler, I(offsetof(Config,sshbug_rsapad2)));
2060 ctrl_droplist(s, "Misuses the session ID in SSH-2 PK auth", 'n', 20,
2061 HELPCTX(ssh_bugs_pksessid2),
2062 sshbug_handler, I(offsetof(Config,sshbug_pksessid2)));
2063 ctrl_droplist(s, "Handles SSH-2 key re-exchange badly", 'k', 20,
2064 HELPCTX(ssh_bugs_rekey2),
2065 sshbug_handler, I(offsetof(Config,sshbug_rekey2)));