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));
568 if (cval > 255) cval = 255;
569 if (cval < 0) cval = 0;
571 i = dlg_listbox_index(cd->listbox, dlg);
573 if (ctrl == cd->redit)
574 cfg->colours[i][0] = cval;
575 else if (ctrl == cd->gedit)
576 cfg->colours[i][1] = cval;
577 else if (ctrl == cd->bedit)
578 cfg->colours[i][2] = cval;
581 } else if (event == EVENT_ACTION) {
582 if (ctrl == cd->button) {
583 int i = dlg_listbox_index(cd->listbox, dlg);
589 * Start a colour selector, which will send us an
590 * EVENT_CALLBACK when it's finished and allow us to
591 * pick up the results.
593 dlg_coloursel_start(ctrl, dlg,
598 } else if (event == EVENT_CALLBACK) {
599 if (ctrl == cd->button) {
600 int i = dlg_listbox_index(cd->listbox, dlg);
602 * Collect the results of the colour selector. Will
603 * return nonzero on success, or zero if the colour
604 * selector did nothing (user hit Cancel, for example).
606 if (dlg_coloursel_results(ctrl, dlg, &r, &g, &b)) {
607 cfg->colours[i][0] = r;
608 cfg->colours[i][1] = g;
609 cfg->colours[i][2] = b;
617 sprintf(buf, "%d", r); dlg_editbox_set(cd->redit, dlg, buf);
618 sprintf(buf, "%d", g); dlg_editbox_set(cd->gedit, dlg, buf);
619 sprintf(buf, "%d", b); dlg_editbox_set(cd->bedit, dlg, buf);
623 struct ttymodes_data {
624 union control *modelist, *valradio, *valbox;
625 union control *addbutton, *rembutton, *listbox;
628 static void ttymodes_handler(union control *ctrl, void *dlg,
629 void *data, int event)
631 Config *cfg = (Config *)data;
632 struct ttymodes_data *td =
633 (struct ttymodes_data *)ctrl->generic.context.p;
635 if (event == EVENT_REFRESH) {
636 if (ctrl == td->listbox) {
637 char *p = cfg->ttymodes;
638 dlg_update_start(ctrl, dlg);
639 dlg_listbox_clear(ctrl, dlg);
641 int tabpos = strchr(p, '\t') - p;
642 char *disp = dupprintf("%.*s\t%s", tabpos, p,
643 (p[tabpos+1] == 'A') ? "(auto)" :
645 dlg_listbox_add(ctrl, dlg, disp);
649 dlg_update_done(ctrl, dlg);
650 } else if (ctrl == td->modelist) {
652 dlg_update_start(ctrl, dlg);
653 dlg_listbox_clear(ctrl, dlg);
654 for (i = 0; ttymodes[i]; i++)
655 dlg_listbox_add(ctrl, dlg, ttymodes[i]);
656 dlg_listbox_select(ctrl, dlg, 0); /* *shrug* */
657 dlg_update_done(ctrl, dlg);
658 } else if (ctrl == td->valradio) {
659 dlg_radiobutton_set(ctrl, dlg, 0);
661 } else if (event == EVENT_ACTION) {
662 if (ctrl == td->addbutton) {
663 int ind = dlg_listbox_index(td->modelist, dlg);
665 char type = dlg_radiobutton_get(td->valradio, dlg) ? 'V' : 'A';
667 char *p, str[lenof(cfg->ttymodes)];
668 /* Construct new entry */
669 memset(str, 0, lenof(str));
670 strncpy(str, ttymodes[ind], lenof(str)-3);
676 dlg_editbox_get(td->valbox, dlg, str+slen, lenof(str)-slen);
678 /* Find end of list, deleting any existing instance */
680 left = lenof(cfg->ttymodes);
682 int t = strchr(p, '\t') - p;
683 if (t == strlen(ttymodes[ind]) &&
684 strncmp(p, ttymodes[ind], t) == 0) {
685 memmove(p, p+strlen(p)+1, left - (strlen(p)+1));
688 left -= strlen(p) + 1;
691 /* Append new entry */
693 strncpy(p, str, left - 2);
694 dlg_refresh(td->listbox, dlg);
697 } else if (ctrl == td->rembutton) {
698 char *p = cfg->ttymodes;
699 int i = 0, len = lenof(cfg->ttymodes);
701 if (dlg_listbox_issel(td->listbox, dlg, i)) {
702 memmove(p, p+strlen(p)+1, len - (strlen(p)+1));
706 len -= strlen(p) + 1;
710 memset(p, 0, lenof(cfg->ttymodes) - len);
711 dlg_refresh(td->listbox, dlg);
716 struct environ_data {
717 union control *varbox, *valbox, *addbutton, *rembutton, *listbox;
720 static void environ_handler(union control *ctrl, void *dlg,
721 void *data, int event)
723 Config *cfg = (Config *)data;
724 struct environ_data *ed =
725 (struct environ_data *)ctrl->generic.context.p;
727 if (event == EVENT_REFRESH) {
728 if (ctrl == ed->listbox) {
729 char *p = cfg->environmt;
730 dlg_update_start(ctrl, dlg);
731 dlg_listbox_clear(ctrl, dlg);
733 dlg_listbox_add(ctrl, dlg, p);
736 dlg_update_done(ctrl, dlg);
738 } else if (event == EVENT_ACTION) {
739 if (ctrl == ed->addbutton) {
740 char str[sizeof(cfg->environmt)];
742 dlg_editbox_get(ed->varbox, dlg, str, sizeof(str)-1);
747 p = str + strlen(str);
749 dlg_editbox_get(ed->valbox, dlg, p, sizeof(str)-1 - (p - str));
760 if ((p - cfg->environmt) + strlen(str) + 2 <
761 sizeof(cfg->environmt)) {
763 p[strlen(str) + 1] = '\0';
764 dlg_listbox_add(ed->listbox, dlg, str);
765 dlg_editbox_set(ed->varbox, dlg, "");
766 dlg_editbox_set(ed->valbox, dlg, "");
768 dlg_error_msg(dlg, "Environment too big");
770 } else if (ctrl == ed->rembutton) {
771 int i = dlg_listbox_index(ed->listbox, dlg);
777 dlg_listbox_del(ed->listbox, dlg, i);
805 struct portfwd_data {
806 union control *addbutton, *rembutton, *listbox;
807 union control *sourcebox, *destbox, *direction;
809 union control *addressfamily;
813 static void portfwd_handler(union control *ctrl, void *dlg,
814 void *data, int event)
816 Config *cfg = (Config *)data;
817 struct portfwd_data *pfd =
818 (struct portfwd_data *)ctrl->generic.context.p;
820 if (event == EVENT_REFRESH) {
821 if (ctrl == pfd->listbox) {
822 char *p = cfg->portfwd;
823 dlg_update_start(ctrl, dlg);
824 dlg_listbox_clear(ctrl, dlg);
826 dlg_listbox_add(ctrl, dlg, p);
829 dlg_update_done(ctrl, dlg);
830 } else if (ctrl == pfd->direction) {
834 dlg_radiobutton_set(ctrl, dlg, 0);
836 } else if (ctrl == pfd->addressfamily) {
837 dlg_radiobutton_set(ctrl, dlg, 0);
840 } else if (event == EVENT_ACTION) {
841 if (ctrl == pfd->addbutton) {
842 char str[sizeof(cfg->portfwd)];
849 whichbutton = dlg_radiobutton_get(pfd->addressfamily, dlg);
850 if (whichbutton == 1)
852 else if (whichbutton == 2)
856 whichbutton = dlg_radiobutton_get(pfd->direction, dlg);
857 if (whichbutton == 0)
859 else if (whichbutton == 1)
865 dlg_editbox_get(pfd->sourcebox, dlg, str+i, sizeof(str) - i);
867 dlg_error_msg(dlg, "You need to specify a source port number");
870 p = str + strlen(str);
873 dlg_editbox_get(pfd->destbox, dlg, p,
874 sizeof(str) - (p - str));
875 if (!*p || !strchr(p, ':')) {
877 "You need to specify a destination address\n"
878 "in the form \"host.name:port\"");
889 if ((p - cfg->portfwd) + strlen(str) + 2 <=
890 sizeof(cfg->portfwd)) {
892 p[strlen(str) + 1] = '\0';
893 dlg_listbox_add(pfd->listbox, dlg, str);
894 dlg_editbox_set(pfd->sourcebox, dlg, "");
895 dlg_editbox_set(pfd->destbox, dlg, "");
897 dlg_error_msg(dlg, "Too many forwardings");
899 } else if (ctrl == pfd->rembutton) {
900 int i = dlg_listbox_index(pfd->listbox, dlg);
906 dlg_listbox_del(pfd->listbox, dlg, i);
934 void setup_config_box(struct controlbox *b, int midsession,
935 int protocol, int protcfginfo)
937 struct controlset *s;
938 struct sessionsaver_data *ssd;
939 struct charclass_data *ccd;
940 struct colour_data *cd;
941 struct ttymodes_data *td;
942 struct environ_data *ed;
943 struct portfwd_data *pfd;
947 ssd = (struct sessionsaver_data *)
948 ctrl_alloc(b, sizeof(struct sessionsaver_data));
949 memset(ssd, 0, sizeof(*ssd));
950 ssd->midsession = midsession;
953 * The standard panel that appears at the bottom of all panels:
954 * Open, Cancel, Apply etc.
956 s = ctrl_getset(b, "", "", "");
957 ctrl_columns(s, 5, 20, 20, 20, 20, 20);
958 ssd->okbutton = ctrl_pushbutton(s,
959 (midsession ? "Apply" : "Open"),
960 (char)(midsession ? 'a' : 'o'),
962 sessionsaver_handler, P(ssd));
963 ssd->okbutton->button.isdefault = TRUE;
964 ssd->okbutton->generic.column = 3;
965 ssd->cancelbutton = ctrl_pushbutton(s, "Cancel", 'c', HELPCTX(no_help),
966 sessionsaver_handler, P(ssd));
967 ssd->cancelbutton->button.iscancel = TRUE;
968 ssd->cancelbutton->generic.column = 4;
969 /* We carefully don't close the 5-column part, so that platform-
970 * specific add-ons can put extra buttons alongside Open and Cancel. */
975 str = dupprintf("Basic options for your %s session", appname);
976 ctrl_settitle(b, "Session", str);
980 s = ctrl_getset(b, "Session", "hostport",
981 "Specify your connection by host name or IP address");
982 ctrl_columns(s, 2, 75, 25);
983 c = ctrl_editbox(s, "Host Name (or IP address)", 'n', 100,
984 HELPCTX(session_hostname),
985 dlg_stdeditbox_handler, I(offsetof(Config,host)),
986 I(sizeof(((Config *)0)->host)));
987 c->generic.column = 0;
988 c = ctrl_editbox(s, "Port", 'p', 100, HELPCTX(session_hostname),
989 dlg_stdeditbox_handler,
990 I(offsetof(Config,port)), I(-1));
991 c->generic.column = 1;
992 ctrl_columns(s, 1, 100);
993 if (backends[3].name == NULL) {
994 ctrl_radiobuttons(s, "Protocol:", NO_SHORTCUT, 3,
995 HELPCTX(session_hostname),
996 protocolbuttons_handler, P(c),
997 "Raw", 'r', I(PROT_RAW),
998 "Telnet", 't', I(PROT_TELNET),
999 "Rlogin", 'i', I(PROT_RLOGIN),
1002 ctrl_radiobuttons(s, "Protocol:", NO_SHORTCUT, 4,
1003 HELPCTX(session_hostname),
1004 protocolbuttons_handler, P(c),
1005 "Raw", 'r', I(PROT_RAW),
1006 "Telnet", 't', I(PROT_TELNET),
1007 "Rlogin", 'i', I(PROT_RLOGIN),
1008 "SSH", 's', I(PROT_SSH),
1014 * The Load/Save panel is available even in mid-session.
1016 s = ctrl_getset(b, "Session", "savedsessions",
1017 midsession ? "Save the current session settings" :
1018 "Load, save or delete a stored session");
1019 ctrl_columns(s, 2, 75, 25);
1020 get_sesslist(&ssd->sesslist, TRUE);
1021 ssd->editbox = ctrl_editbox(s, "Saved Sessions", 'e', 100,
1022 HELPCTX(session_saved),
1023 sessionsaver_handler, P(ssd), P(NULL));
1024 ssd->editbox->generic.column = 0;
1025 /* Reset columns so that the buttons are alongside the list, rather
1026 * than alongside that edit box. */
1027 ctrl_columns(s, 1, 100);
1028 ctrl_columns(s, 2, 75, 25);
1029 ssd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1030 HELPCTX(session_saved),
1031 sessionsaver_handler, P(ssd));
1032 ssd->listbox->generic.column = 0;
1033 ssd->listbox->listbox.height = 7;
1035 ssd->loadbutton = ctrl_pushbutton(s, "Load", 'l',
1036 HELPCTX(session_saved),
1037 sessionsaver_handler, P(ssd));
1038 ssd->loadbutton->generic.column = 1;
1040 /* We can't offer the Load button mid-session, as it would allow the
1041 * user to load and subsequently save settings they can't see. (And
1042 * also change otherwise immutable settings underfoot; that probably
1043 * shouldn't be a problem, but.) */
1044 ssd->loadbutton = NULL;
1046 /* "Save" button is permitted mid-session. */
1047 ssd->savebutton = ctrl_pushbutton(s, "Save", 'v',
1048 HELPCTX(session_saved),
1049 sessionsaver_handler, P(ssd));
1050 ssd->savebutton->generic.column = 1;
1052 ssd->delbutton = ctrl_pushbutton(s, "Delete", 'd',
1053 HELPCTX(session_saved),
1054 sessionsaver_handler, P(ssd));
1055 ssd->delbutton->generic.column = 1;
1057 /* Disable the Delete button mid-session too, for UI consistency. */
1058 ssd->delbutton = NULL;
1060 ctrl_columns(s, 1, 100);
1062 s = ctrl_getset(b, "Session", "otheropts", NULL);
1063 c = ctrl_radiobuttons(s, "Close window on exit:", 'w', 4,
1064 HELPCTX(session_coe),
1065 dlg_stdradiobutton_handler,
1066 I(offsetof(Config, close_on_exit)),
1067 "Always", I(FORCE_ON),
1068 "Never", I(FORCE_OFF),
1069 "Only on clean exit", I(AUTO), NULL);
1072 * The Session/Logging panel.
1074 ctrl_settitle(b, "Session/Logging", "Options controlling session logging");
1076 s = ctrl_getset(b, "Session/Logging", "main", NULL);
1078 * The logging buttons change depending on whether SSH packet
1079 * logging can sensibly be available.
1083 if ((midsession && protocol == PROT_SSH) ||
1084 (!midsession && backends[3].name != NULL))
1085 sshlogname = "Log SSH packet data";
1087 sshlogname = NULL; /* this will disable the button */
1088 ctrl_radiobuttons(s, "Session logging:", NO_SHORTCUT, 1,
1089 HELPCTX(logging_main),
1090 loggingbuttons_handler,
1091 I(offsetof(Config, logtype)),
1092 "Logging turned off completely", 't', I(LGTYP_NONE),
1093 "Log printable output only", 'p', I(LGTYP_ASCII),
1094 "Log all session output", 'l', I(LGTYP_DEBUG),
1095 sshlogname, 's', I(LGTYP_PACKETS),
1098 ctrl_filesel(s, "Log file name:", 'f',
1099 NULL, TRUE, "Select session log file name",
1100 HELPCTX(logging_filename),
1101 dlg_stdfilesel_handler, I(offsetof(Config, logfilename)));
1102 ctrl_text(s, "(Log file name can contain &Y, &M, &D for date,"
1103 " &T for time, and &H for host name)",
1104 HELPCTX(logging_filename));
1105 ctrl_radiobuttons(s, "What to do if the log file already exists:", 'e', 1,
1106 HELPCTX(logging_exists),
1107 dlg_stdradiobutton_handler, I(offsetof(Config,logxfovr)),
1108 "Always overwrite it", I(LGXF_OVR),
1109 "Always append to the end of it", I(LGXF_APN),
1110 "Ask the user every time", I(LGXF_ASK), NULL);
1111 ctrl_checkbox(s, "Flush log file frequently", 'u',
1112 HELPCTX(logging_flush),
1113 dlg_stdcheckbox_handler, I(offsetof(Config,logflush)));
1115 if ((midsession && protocol == PROT_SSH) ||
1116 (!midsession && backends[3].name != NULL)) {
1117 s = ctrl_getset(b, "Session/Logging", "ssh",
1118 "Options specific to SSH packet logging");
1119 ctrl_checkbox(s, "Omit known password fields", 'k',
1120 HELPCTX(logging_ssh_omit_password),
1121 dlg_stdcheckbox_handler, I(offsetof(Config,logomitpass)));
1122 ctrl_checkbox(s, "Omit session data", 'd',
1123 HELPCTX(logging_ssh_omit_data),
1124 dlg_stdcheckbox_handler, I(offsetof(Config,logomitdata)));
1128 * The Terminal panel.
1130 ctrl_settitle(b, "Terminal", "Options controlling the terminal emulation");
1132 s = ctrl_getset(b, "Terminal", "general", "Set various terminal options");
1133 ctrl_checkbox(s, "Auto wrap mode initially on", 'w',
1134 HELPCTX(terminal_autowrap),
1135 dlg_stdcheckbox_handler, I(offsetof(Config,wrap_mode)));
1136 ctrl_checkbox(s, "DEC Origin Mode initially on", 'd',
1137 HELPCTX(terminal_decom),
1138 dlg_stdcheckbox_handler, I(offsetof(Config,dec_om)));
1139 ctrl_checkbox(s, "Implicit CR in every LF", 'r',
1140 HELPCTX(terminal_lfhascr),
1141 dlg_stdcheckbox_handler, I(offsetof(Config,lfhascr)));
1142 ctrl_checkbox(s, "Use background colour to erase screen", 'e',
1143 HELPCTX(terminal_bce),
1144 dlg_stdcheckbox_handler, I(offsetof(Config,bce)));
1145 ctrl_checkbox(s, "Enable blinking text", 'n',
1146 HELPCTX(terminal_blink),
1147 dlg_stdcheckbox_handler, I(offsetof(Config,blinktext)));
1148 ctrl_editbox(s, "Answerback to ^E:", 's', 100,
1149 HELPCTX(terminal_answerback),
1150 dlg_stdeditbox_handler, I(offsetof(Config,answerback)),
1151 I(sizeof(((Config *)0)->answerback)));
1153 s = ctrl_getset(b, "Terminal", "ldisc", "Line discipline options");
1154 ctrl_radiobuttons(s, "Local echo:", 'l', 3,
1155 HELPCTX(terminal_localecho),
1156 dlg_stdradiobutton_handler,I(offsetof(Config,localecho)),
1158 "Force on", I(FORCE_ON),
1159 "Force off", I(FORCE_OFF), NULL);
1160 ctrl_radiobuttons(s, "Local line editing:", 't', 3,
1161 HELPCTX(terminal_localedit),
1162 dlg_stdradiobutton_handler,I(offsetof(Config,localedit)),
1164 "Force on", I(FORCE_ON),
1165 "Force off", I(FORCE_OFF), NULL);
1167 s = ctrl_getset(b, "Terminal", "printing", "Remote-controlled printing");
1168 ctrl_combobox(s, "Printer to send ANSI printer output to:", 'p', 100,
1169 HELPCTX(terminal_printing),
1170 printerbox_handler, P(NULL), P(NULL));
1173 * The Terminal/Keyboard panel.
1175 ctrl_settitle(b, "Terminal/Keyboard",
1176 "Options controlling the effects of keys");
1178 s = ctrl_getset(b, "Terminal/Keyboard", "mappings",
1179 "Change the sequences sent by:");
1180 ctrl_radiobuttons(s, "The Backspace key", 'b', 2,
1181 HELPCTX(keyboard_backspace),
1182 dlg_stdradiobutton_handler,
1183 I(offsetof(Config, bksp_is_delete)),
1184 "Control-H", I(0), "Control-? (127)", I(1), NULL);
1185 ctrl_radiobuttons(s, "The Home and End keys", 'e', 2,
1186 HELPCTX(keyboard_homeend),
1187 dlg_stdradiobutton_handler,
1188 I(offsetof(Config, rxvt_homeend)),
1189 "Standard", I(0), "rxvt", I(1), NULL);
1190 ctrl_radiobuttons(s, "The Function keys and keypad", 'f', 3,
1191 HELPCTX(keyboard_funkeys),
1192 dlg_stdradiobutton_handler,
1193 I(offsetof(Config, funky_type)),
1194 "ESC[n~", I(0), "Linux", I(1), "Xterm R6", I(2),
1195 "VT400", I(3), "VT100+", I(4), "SCO", I(5), NULL);
1197 s = ctrl_getset(b, "Terminal/Keyboard", "appkeypad",
1198 "Application keypad settings:");
1199 ctrl_radiobuttons(s, "Initial state of cursor keys:", 'r', 3,
1200 HELPCTX(keyboard_appcursor),
1201 dlg_stdradiobutton_handler,
1202 I(offsetof(Config, app_cursor)),
1203 "Normal", I(0), "Application", I(1), NULL);
1204 ctrl_radiobuttons(s, "Initial state of numeric keypad:", 'n', 3,
1205 HELPCTX(keyboard_appkeypad),
1206 numeric_keypad_handler, P(NULL),
1207 "Normal", I(0), "Application", I(1), "NetHack", I(2),
1211 * The Terminal/Bell panel.
1213 ctrl_settitle(b, "Terminal/Bell",
1214 "Options controlling the terminal bell");
1216 s = ctrl_getset(b, "Terminal/Bell", "style", "Set the style of bell");
1217 ctrl_radiobuttons(s, "Action to happen when a bell occurs:", 'b', 1,
1218 HELPCTX(bell_style),
1219 dlg_stdradiobutton_handler, I(offsetof(Config, beep)),
1220 "None (bell disabled)", I(BELL_DISABLED),
1221 "Make default system alert sound", I(BELL_DEFAULT),
1222 "Visual bell (flash window)", I(BELL_VISUAL), NULL);
1224 s = ctrl_getset(b, "Terminal/Bell", "overload",
1225 "Control the bell overload behaviour");
1226 ctrl_checkbox(s, "Bell is temporarily disabled when over-used", 'd',
1227 HELPCTX(bell_overload),
1228 dlg_stdcheckbox_handler, I(offsetof(Config,bellovl)));
1229 ctrl_editbox(s, "Over-use means this many bells...", 'm', 20,
1230 HELPCTX(bell_overload),
1231 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_n)), I(-1));
1232 ctrl_editbox(s, "... in this many seconds", 't', 20,
1233 HELPCTX(bell_overload),
1234 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_t)),
1236 ctrl_text(s, "The bell is re-enabled after a few seconds of silence.",
1237 HELPCTX(bell_overload));
1238 ctrl_editbox(s, "Seconds of silence required", 's', 20,
1239 HELPCTX(bell_overload),
1240 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_s)),
1244 * The Terminal/Features panel.
1246 ctrl_settitle(b, "Terminal/Features",
1247 "Enabling and disabling advanced terminal features");
1249 s = ctrl_getset(b, "Terminal/Features", "main", NULL);
1250 ctrl_checkbox(s, "Disable application cursor keys mode", 'u',
1251 HELPCTX(features_application),
1252 dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_c)));
1253 ctrl_checkbox(s, "Disable application keypad mode", 'k',
1254 HELPCTX(features_application),
1255 dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_k)));
1256 ctrl_checkbox(s, "Disable xterm-style mouse reporting", 'x',
1257 HELPCTX(features_mouse),
1258 dlg_stdcheckbox_handler, I(offsetof(Config,no_mouse_rep)));
1259 ctrl_checkbox(s, "Disable remote-controlled terminal resizing", 's',
1260 HELPCTX(features_resize),
1261 dlg_stdcheckbox_handler,
1262 I(offsetof(Config,no_remote_resize)));
1263 ctrl_checkbox(s, "Disable switching to alternate terminal screen", 'w',
1264 HELPCTX(features_altscreen),
1265 dlg_stdcheckbox_handler, I(offsetof(Config,no_alt_screen)));
1266 ctrl_checkbox(s, "Disable remote-controlled window title changing", 't',
1267 HELPCTX(features_retitle),
1268 dlg_stdcheckbox_handler,
1269 I(offsetof(Config,no_remote_wintitle)));
1270 ctrl_checkbox(s, "Disable remote window title querying (SECURITY)",
1271 'q', HELPCTX(features_qtitle), dlg_stdcheckbox_handler,
1272 I(offsetof(Config,no_remote_qtitle)));
1273 ctrl_checkbox(s, "Disable destructive backspace on server sending ^?",'b',
1274 HELPCTX(features_dbackspace),
1275 dlg_stdcheckbox_handler, I(offsetof(Config,no_dbackspace)));
1276 ctrl_checkbox(s, "Disable remote-controlled character set configuration",
1277 'r', HELPCTX(features_charset), dlg_stdcheckbox_handler,
1278 I(offsetof(Config,no_remote_charset)));
1279 ctrl_checkbox(s, "Disable Arabic text shaping",
1280 'l', HELPCTX(features_arabicshaping), dlg_stdcheckbox_handler,
1281 I(offsetof(Config, arabicshaping)));
1282 ctrl_checkbox(s, "Disable bidirectional text display",
1283 'd', HELPCTX(features_bidi), dlg_stdcheckbox_handler,
1284 I(offsetof(Config, bidi)));
1289 str = dupprintf("Options controlling %s's window", appname);
1290 ctrl_settitle(b, "Window", str);
1293 s = ctrl_getset(b, "Window", "size", "Set the size of the window");
1294 ctrl_columns(s, 2, 50, 50);
1295 c = ctrl_editbox(s, "Rows", 'r', 100,
1296 HELPCTX(window_size),
1297 dlg_stdeditbox_handler, I(offsetof(Config,height)),I(-1));
1298 c->generic.column = 0;
1299 c = ctrl_editbox(s, "Columns", 'm', 100,
1300 HELPCTX(window_size),
1301 dlg_stdeditbox_handler, I(offsetof(Config,width)), I(-1));
1302 c->generic.column = 1;
1303 ctrl_columns(s, 1, 100);
1305 s = ctrl_getset(b, "Window", "scrollback",
1306 "Control the scrollback in the window");
1307 ctrl_editbox(s, "Lines of scrollback", 's', 50,
1308 HELPCTX(window_scrollback),
1309 dlg_stdeditbox_handler, I(offsetof(Config,savelines)), I(-1));
1310 ctrl_checkbox(s, "Display scrollbar", 'd',
1311 HELPCTX(window_scrollback),
1312 dlg_stdcheckbox_handler, I(offsetof(Config,scrollbar)));
1313 ctrl_checkbox(s, "Reset scrollback on keypress", 'k',
1314 HELPCTX(window_scrollback),
1315 dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_key)));
1316 ctrl_checkbox(s, "Reset scrollback on display activity", 'p',
1317 HELPCTX(window_scrollback),
1318 dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_disp)));
1319 ctrl_checkbox(s, "Push erased text into scrollback", 'e',
1320 HELPCTX(window_erased),
1321 dlg_stdcheckbox_handler,
1322 I(offsetof(Config,erase_to_scrollback)));
1325 * The Window/Appearance panel.
1327 str = dupprintf("Configure the appearance of %s's window", appname);
1328 ctrl_settitle(b, "Window/Appearance", str);
1331 s = ctrl_getset(b, "Window/Appearance", "cursor",
1332 "Adjust the use of the cursor");
1333 ctrl_radiobuttons(s, "Cursor appearance:", NO_SHORTCUT, 3,
1334 HELPCTX(appearance_cursor),
1335 dlg_stdradiobutton_handler,
1336 I(offsetof(Config, cursor_type)),
1338 "Underline", 'u', I(1),
1339 "Vertical line", 'v', I(2), NULL);
1340 ctrl_checkbox(s, "Cursor blinks", 'b',
1341 HELPCTX(appearance_cursor),
1342 dlg_stdcheckbox_handler, I(offsetof(Config,blink_cur)));
1344 s = ctrl_getset(b, "Window/Appearance", "font",
1346 ctrl_fontsel(s, "Font used in the terminal window", 'n',
1347 HELPCTX(appearance_font),
1348 dlg_stdfontsel_handler, I(offsetof(Config, font)));
1350 s = ctrl_getset(b, "Window/Appearance", "mouse",
1351 "Adjust the use of the mouse pointer");
1352 ctrl_checkbox(s, "Hide mouse pointer when typing in window", 'p',
1353 HELPCTX(appearance_hidemouse),
1354 dlg_stdcheckbox_handler, I(offsetof(Config,hide_mouseptr)));
1356 s = ctrl_getset(b, "Window/Appearance", "border",
1357 "Adjust the window border");
1358 ctrl_editbox(s, "Gap between text and window edge:", 'e', 20,
1359 HELPCTX(appearance_border),
1360 dlg_stdeditbox_handler,
1361 I(offsetof(Config,window_border)), I(-1));
1364 * The Window/Behaviour panel.
1366 str = dupprintf("Configure the behaviour of %s's window", appname);
1367 ctrl_settitle(b, "Window/Behaviour", str);
1370 s = ctrl_getset(b, "Window/Behaviour", "title",
1371 "Adjust the behaviour of the window title");
1372 ctrl_editbox(s, "Window title:", 't', 100,
1373 HELPCTX(appearance_title),
1374 dlg_stdeditbox_handler, I(offsetof(Config,wintitle)),
1375 I(sizeof(((Config *)0)->wintitle)));
1376 ctrl_checkbox(s, "Separate window and icon titles", 'i',
1377 HELPCTX(appearance_title),
1378 dlg_stdcheckbox_handler,
1379 I(CHECKBOX_INVERT | offsetof(Config,win_name_always)));
1381 s = ctrl_getset(b, "Window/Behaviour", "main", NULL);
1382 ctrl_checkbox(s, "Warn before closing window", 'w',
1383 HELPCTX(behaviour_closewarn),
1384 dlg_stdcheckbox_handler, I(offsetof(Config,warn_on_close)));
1387 * The Window/Translation panel.
1389 ctrl_settitle(b, "Window/Translation",
1390 "Options controlling character set translation");
1392 s = ctrl_getset(b, "Window/Translation", "trans",
1393 "Character set translation on received data");
1394 ctrl_combobox(s, "Received data assumed to be in which character set:",
1395 'r', 100, HELPCTX(translation_codepage),
1396 codepage_handler, P(NULL), P(NULL));
1398 s = ctrl_getset(b, "Window/Translation", "tweaks", NULL);
1399 ctrl_checkbox(s, "Treat CJK ambiguous characters as wide", 'w',
1400 HELPCTX(translation_cjk_ambig_wide),
1401 dlg_stdcheckbox_handler, I(offsetof(Config,cjk_ambig_wide)));
1403 str = dupprintf("Adjust how %s handles line drawing characters", appname);
1404 s = ctrl_getset(b, "Window/Translation", "linedraw", str);
1406 ctrl_radiobuttons(s, "Handling of line drawing characters:", NO_SHORTCUT,1,
1407 HELPCTX(translation_linedraw),
1408 dlg_stdradiobutton_handler,
1409 I(offsetof(Config, vtmode)),
1410 "Use Unicode line drawing code points",'u',I(VT_UNICODE),
1411 "Poor man's line drawing (+, - and |)",'p',I(VT_POORMAN),
1413 ctrl_checkbox(s, "Copy and paste line drawing characters as lqqqk",'d',
1414 HELPCTX(selection_linedraw),
1415 dlg_stdcheckbox_handler, I(offsetof(Config,rawcnp)));
1418 * The Window/Selection panel.
1420 ctrl_settitle(b, "Window/Selection", "Options controlling copy and paste");
1422 s = ctrl_getset(b, "Window/Selection", "mouse",
1423 "Control use of mouse");
1424 ctrl_checkbox(s, "Shift overrides application's use of mouse", 'p',
1425 HELPCTX(selection_shiftdrag),
1426 dlg_stdcheckbox_handler, I(offsetof(Config,mouse_override)));
1427 ctrl_radiobuttons(s,
1428 "Default selection mode (Alt+drag does the other one):",
1430 HELPCTX(selection_rect),
1431 dlg_stdradiobutton_handler,
1432 I(offsetof(Config, rect_select)),
1433 "Normal", 'n', I(0),
1434 "Rectangular block", 'r', I(1), NULL);
1436 s = ctrl_getset(b, "Window/Selection", "charclass",
1437 "Control the select-one-word-at-a-time mode");
1438 ccd = (struct charclass_data *)
1439 ctrl_alloc(b, sizeof(struct charclass_data));
1440 ccd->listbox = ctrl_listbox(s, "Character classes:", 'e',
1441 HELPCTX(selection_charclasses),
1442 charclass_handler, P(ccd));
1443 ccd->listbox->listbox.multisel = 1;
1444 ccd->listbox->listbox.ncols = 4;
1445 ccd->listbox->listbox.percentages = snewn(4, int);
1446 ccd->listbox->listbox.percentages[0] = 15;
1447 ccd->listbox->listbox.percentages[1] = 25;
1448 ccd->listbox->listbox.percentages[2] = 20;
1449 ccd->listbox->listbox.percentages[3] = 40;
1450 ctrl_columns(s, 2, 67, 33);
1451 ccd->editbox = ctrl_editbox(s, "Set to class", 't', 50,
1452 HELPCTX(selection_charclasses),
1453 charclass_handler, P(ccd), P(NULL));
1454 ccd->editbox->generic.column = 0;
1455 ccd->button = ctrl_pushbutton(s, "Set", 's',
1456 HELPCTX(selection_charclasses),
1457 charclass_handler, P(ccd));
1458 ccd->button->generic.column = 1;
1459 ctrl_columns(s, 1, 100);
1462 * The Window/Colours panel.
1464 ctrl_settitle(b, "Window/Colours", "Options controlling use of colours");
1466 s = ctrl_getset(b, "Window/Colours", "general",
1467 "General options for colour usage");
1468 ctrl_checkbox(s, "Allow terminal to specify ANSI colours", 'i',
1469 HELPCTX(colours_ansi),
1470 dlg_stdcheckbox_handler, I(offsetof(Config,ansi_colour)));
1471 ctrl_checkbox(s, "Allow terminal to use xterm 256-colour mode", '2',
1472 HELPCTX(colours_xterm256), dlg_stdcheckbox_handler,
1473 I(offsetof(Config,xterm_256_colour)));
1474 ctrl_checkbox(s, "Bolded text is a different colour", 'b',
1475 HELPCTX(colours_bold),
1476 dlg_stdcheckbox_handler, I(offsetof(Config,bold_colour)));
1478 str = dupprintf("Adjust the precise colours %s displays", appname);
1479 s = ctrl_getset(b, "Window/Colours", "adjust", str);
1481 ctrl_text(s, "Select a colour from the list, and then click the"
1482 " Modify button to change its appearance.",
1483 HELPCTX(colours_config));
1484 ctrl_columns(s, 2, 67, 33);
1485 cd = (struct colour_data *)ctrl_alloc(b, sizeof(struct colour_data));
1486 cd->listbox = ctrl_listbox(s, "Select a colour to adjust:", 'u',
1487 HELPCTX(colours_config), colour_handler, P(cd));
1488 cd->listbox->generic.column = 0;
1489 cd->listbox->listbox.height = 7;
1490 c = ctrl_text(s, "RGB value:", HELPCTX(colours_config));
1491 c->generic.column = 1;
1492 cd->redit = ctrl_editbox(s, "Red", 'r', 50, HELPCTX(colours_config),
1493 colour_handler, P(cd), P(NULL));
1494 cd->redit->generic.column = 1;
1495 cd->gedit = ctrl_editbox(s, "Green", 'n', 50, HELPCTX(colours_config),
1496 colour_handler, P(cd), P(NULL));
1497 cd->gedit->generic.column = 1;
1498 cd->bedit = ctrl_editbox(s, "Blue", 'e', 50, HELPCTX(colours_config),
1499 colour_handler, P(cd), P(NULL));
1500 cd->bedit->generic.column = 1;
1501 cd->button = ctrl_pushbutton(s, "Modify", 'm', HELPCTX(colours_config),
1502 colour_handler, P(cd));
1503 cd->button->generic.column = 1;
1504 ctrl_columns(s, 1, 100);
1507 * The Connection panel. This doesn't show up if we're in a
1508 * non-network utility such as pterm. We tell this by being
1509 * passed a protocol < 0.
1511 if (protocol >= 0) {
1512 ctrl_settitle(b, "Connection", "Options controlling the connection");
1514 s = ctrl_getset(b, "Connection", "keepalive",
1515 "Sending of null packets to keep session active");
1516 ctrl_editbox(s, "Seconds between keepalives (0 to turn off)", 'k', 20,
1517 HELPCTX(connection_keepalive),
1518 dlg_stdeditbox_handler, I(offsetof(Config,ping_interval)),
1522 s = ctrl_getset(b, "Connection", "tcp",
1523 "Low-level TCP connection options");
1524 ctrl_checkbox(s, "Disable Nagle's algorithm (TCP_NODELAY option)",
1525 'n', HELPCTX(connection_nodelay),
1526 dlg_stdcheckbox_handler,
1527 I(offsetof(Config,tcp_nodelay)));
1528 ctrl_checkbox(s, "Enable TCP keepalives (SO_KEEPALIVE option)",
1529 'p', HELPCTX(connection_tcpkeepalive),
1530 dlg_stdcheckbox_handler,
1531 I(offsetof(Config,tcp_keepalives)));
1533 s = ctrl_getset(b, "Connection", "ipversion",
1534 "Internet protocol version");
1535 ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
1536 HELPCTX(connection_ipversion),
1537 dlg_stdradiobutton_handler,
1538 I(offsetof(Config, addressfamily)),
1539 "Auto", 'u', I(ADDRTYPE_UNSPEC),
1540 "IPv4", '4', I(ADDRTYPE_IPV4),
1541 "IPv6", '6', I(ADDRTYPE_IPV6),
1547 * A sub-panel Connection/Data, containing options that
1548 * decide on data to send to the server.
1551 ctrl_settitle(b, "Connection/Data", "Data to send to the server");
1553 s = ctrl_getset(b, "Connection/Data", "login",
1555 ctrl_editbox(s, "Auto-login username", 'u', 50,
1556 HELPCTX(connection_username),
1557 dlg_stdeditbox_handler, I(offsetof(Config,username)),
1558 I(sizeof(((Config *)0)->username)));
1560 s = ctrl_getset(b, "Connection/Data", "term",
1561 "Terminal details");
1562 ctrl_editbox(s, "Terminal-type string", 't', 50,
1563 HELPCTX(connection_termtype),
1564 dlg_stdeditbox_handler, I(offsetof(Config,termtype)),
1565 I(sizeof(((Config *)0)->termtype)));
1566 ctrl_editbox(s, "Terminal speeds", 's', 50,
1567 HELPCTX(connection_termspeed),
1568 dlg_stdeditbox_handler, I(offsetof(Config,termspeed)),
1569 I(sizeof(((Config *)0)->termspeed)));
1571 s = ctrl_getset(b, "Connection/Data", "env",
1572 "Environment variables");
1573 ctrl_columns(s, 2, 80, 20);
1574 ed = (struct environ_data *)
1575 ctrl_alloc(b, sizeof(struct environ_data));
1576 ed->varbox = ctrl_editbox(s, "Variable", 'v', 60,
1577 HELPCTX(telnet_environ),
1578 environ_handler, P(ed), P(NULL));
1579 ed->varbox->generic.column = 0;
1580 ed->valbox = ctrl_editbox(s, "Value", 'l', 60,
1581 HELPCTX(telnet_environ),
1582 environ_handler, P(ed), P(NULL));
1583 ed->valbox->generic.column = 0;
1584 ed->addbutton = ctrl_pushbutton(s, "Add", 'd',
1585 HELPCTX(telnet_environ),
1586 environ_handler, P(ed));
1587 ed->addbutton->generic.column = 1;
1588 ed->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1589 HELPCTX(telnet_environ),
1590 environ_handler, P(ed));
1591 ed->rembutton->generic.column = 1;
1592 ctrl_columns(s, 1, 100);
1593 ed->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1594 HELPCTX(telnet_environ),
1595 environ_handler, P(ed));
1596 ed->listbox->listbox.height = 3;
1597 ed->listbox->listbox.ncols = 2;
1598 ed->listbox->listbox.percentages = snewn(2, int);
1599 ed->listbox->listbox.percentages[0] = 30;
1600 ed->listbox->listbox.percentages[1] = 70;
1607 * The Connection/Proxy panel.
1609 ctrl_settitle(b, "Connection/Proxy",
1610 "Options controlling proxy usage");
1612 s = ctrl_getset(b, "Connection/Proxy", "basics", NULL);
1613 ctrl_radiobuttons(s, "Proxy type:", 't', 3,
1614 HELPCTX(proxy_type),
1615 dlg_stdradiobutton_handler,
1616 I(offsetof(Config, proxy_type)),
1617 "None", I(PROXY_NONE),
1618 "SOCKS 4", I(PROXY_SOCKS4),
1619 "SOCKS 5", I(PROXY_SOCKS5),
1620 "HTTP", I(PROXY_HTTP),
1621 "Telnet", I(PROXY_TELNET),
1623 ctrl_columns(s, 2, 80, 20);
1624 c = ctrl_editbox(s, "Proxy hostname", 'y', 100,
1625 HELPCTX(proxy_main),
1626 dlg_stdeditbox_handler,
1627 I(offsetof(Config,proxy_host)),
1628 I(sizeof(((Config *)0)->proxy_host)));
1629 c->generic.column = 0;
1630 c = ctrl_editbox(s, "Port", 'p', 100,
1631 HELPCTX(proxy_main),
1632 dlg_stdeditbox_handler,
1633 I(offsetof(Config,proxy_port)),
1635 c->generic.column = 1;
1636 ctrl_columns(s, 1, 100);
1637 ctrl_editbox(s, "Exclude Hosts/IPs", 'e', 100,
1638 HELPCTX(proxy_exclude),
1639 dlg_stdeditbox_handler,
1640 I(offsetof(Config,proxy_exclude_list)),
1641 I(sizeof(((Config *)0)->proxy_exclude_list)));
1642 ctrl_checkbox(s, "Consider proxying local host connections", 'x',
1643 HELPCTX(proxy_exclude),
1644 dlg_stdcheckbox_handler,
1645 I(offsetof(Config,even_proxy_localhost)));
1646 ctrl_radiobuttons(s, "Do DNS name lookup at proxy end:", 'd', 3,
1648 dlg_stdradiobutton_handler,
1649 I(offsetof(Config, proxy_dns)),
1652 "Yes", I(FORCE_ON), NULL);
1653 ctrl_editbox(s, "Username", 'u', 60,
1654 HELPCTX(proxy_auth),
1655 dlg_stdeditbox_handler,
1656 I(offsetof(Config,proxy_username)),
1657 I(sizeof(((Config *)0)->proxy_username)));
1658 c = ctrl_editbox(s, "Password", 'w', 60,
1659 HELPCTX(proxy_auth),
1660 dlg_stdeditbox_handler,
1661 I(offsetof(Config,proxy_password)),
1662 I(sizeof(((Config *)0)->proxy_password)));
1663 c->editbox.password = 1;
1664 ctrl_editbox(s, "Telnet command", 'm', 100,
1665 HELPCTX(proxy_command),
1666 dlg_stdeditbox_handler,
1667 I(offsetof(Config,proxy_telnet_command)),
1668 I(sizeof(((Config *)0)->proxy_telnet_command)));
1672 * The Telnet panel exists in the base config box, and in a
1673 * mid-session reconfig box _if_ we're using Telnet.
1675 if (!midsession || protocol == PROT_TELNET) {
1677 * The Connection/Telnet panel.
1679 ctrl_settitle(b, "Connection/Telnet",
1680 "Options controlling Telnet connections");
1682 s = ctrl_getset(b, "Connection/Telnet", "protocol",
1683 "Telnet protocol adjustments");
1686 ctrl_radiobuttons(s, "Handling of OLD_ENVIRON ambiguity:",
1688 HELPCTX(telnet_oldenviron),
1689 dlg_stdradiobutton_handler,
1690 I(offsetof(Config, rfc_environ)),
1691 "BSD (commonplace)", 'b', I(0),
1692 "RFC 1408 (unusual)", 'f', I(1), NULL);
1693 ctrl_radiobuttons(s, "Telnet negotiation mode:", 't', 2,
1694 HELPCTX(telnet_passive),
1695 dlg_stdradiobutton_handler,
1696 I(offsetof(Config, passive_telnet)),
1697 "Passive", I(1), "Active", I(0), NULL);
1699 ctrl_checkbox(s, "Keyboard sends Telnet special commands", 'k',
1700 HELPCTX(telnet_specialkeys),
1701 dlg_stdcheckbox_handler,
1702 I(offsetof(Config,telnet_keyboard)));
1703 ctrl_checkbox(s, "Return key sends Telnet New Line instead of ^M",
1704 'm', HELPCTX(telnet_newline),
1705 dlg_stdcheckbox_handler,
1706 I(offsetof(Config,telnet_newline)));
1712 * The Connection/Rlogin panel.
1714 ctrl_settitle(b, "Connection/Rlogin",
1715 "Options controlling Rlogin connections");
1717 s = ctrl_getset(b, "Connection/Rlogin", "data",
1718 "Data to send to the server");
1719 ctrl_editbox(s, "Local username:", 'l', 50,
1720 HELPCTX(rlogin_localuser),
1721 dlg_stdeditbox_handler, I(offsetof(Config,localusername)),
1722 I(sizeof(((Config *)0)->localusername)));
1727 * All the SSH stuff is omitted in PuTTYtel, or in a reconfig
1728 * when we're not doing SSH.
1731 if (backends[3].name != NULL && (!midsession || protocol == PROT_SSH)) {
1734 * The Connection/SSH panel.
1736 ctrl_settitle(b, "Connection/SSH",
1737 "Options controlling SSH connections");
1739 if (midsession && protcfginfo == 1) {
1740 s = ctrl_getset(b, "Connection/SSH", "disclaimer", NULL);
1741 ctrl_text(s, "Nothing on this panel may be reconfigured in mid-"
1742 "session; it is only here so that sub-panels of it can "
1743 "exist without looking strange.", HELPCTX(no_help));
1748 s = ctrl_getset(b, "Connection/SSH", "data",
1749 "Data to send to the server");
1750 ctrl_editbox(s, "Remote command:", 'r', 100,
1751 HELPCTX(ssh_command),
1752 dlg_stdeditbox_handler, I(offsetof(Config,remote_cmd)),
1753 I(sizeof(((Config *)0)->remote_cmd)));
1755 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1756 ctrl_checkbox(s, "Don't start a shell or command at all", 'n',
1757 HELPCTX(ssh_noshell),
1758 dlg_stdcheckbox_handler,
1759 I(offsetof(Config,ssh_no_shell)));
1762 if (!midsession || protcfginfo != 1) {
1763 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1765 ctrl_checkbox(s, "Enable compression", 'e',
1766 HELPCTX(ssh_compress),
1767 dlg_stdcheckbox_handler,
1768 I(offsetof(Config,compression)));
1772 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1774 ctrl_radiobuttons(s, "Preferred SSH protocol version:", NO_SHORTCUT, 4,
1775 HELPCTX(ssh_protocol),
1776 dlg_stdradiobutton_handler,
1777 I(offsetof(Config, sshprot)),
1778 "1 only", 'l', I(0),
1781 "2 only", 'y', I(3), NULL);
1784 if (!midsession || protcfginfo != 1) {
1785 s = ctrl_getset(b, "Connection/SSH", "encryption", "Encryption options");
1786 c = ctrl_draglist(s, "Encryption cipher selection policy:", 's',
1787 HELPCTX(ssh_ciphers),
1788 cipherlist_handler, P(NULL));
1789 c->listbox.height = 6;
1791 ctrl_checkbox(s, "Enable legacy use of single-DES in SSH-2", 'i',
1792 HELPCTX(ssh_ciphers),
1793 dlg_stdcheckbox_handler,
1794 I(offsetof(Config,ssh2_des_cbc)));
1798 * The Connection/SSH/Kex panel. (Owing to repeat key
1799 * exchange, this is all meaningful in mid-session _if_
1800 * we're using SSH-2 or haven't decided yet.)
1802 if (protcfginfo != 1) {
1803 ctrl_settitle(b, "Connection/SSH/Kex",
1804 "Options controlling SSH key exchange");
1806 s = ctrl_getset(b, "Connection/SSH/Kex", "main",
1807 "Key exchange algorithm options");
1808 c = ctrl_draglist(s, "Algorithm selection policy:", 's',
1809 HELPCTX(ssh_kexlist),
1810 kexlist_handler, P(NULL));
1811 c->listbox.height = 5;
1813 s = ctrl_getset(b, "Connection/SSH/Kex", "repeat",
1814 "Options controlling key re-exchange");
1816 ctrl_editbox(s, "Max minutes before rekey (0 for no limit)", 't', 20,
1817 HELPCTX(ssh_kex_repeat),
1818 dlg_stdeditbox_handler,
1819 I(offsetof(Config,ssh_rekey_time)),
1821 ctrl_editbox(s, "Max data before rekey (0 for no limit)", 'x', 20,
1822 HELPCTX(ssh_kex_repeat),
1823 dlg_stdeditbox_handler,
1824 I(offsetof(Config,ssh_rekey_data)),
1826 ctrl_text(s, "(Use 1M for 1 megabyte, 1G for 1 gigabyte etc)",
1827 HELPCTX(ssh_kex_repeat));
1833 * The Connection/SSH/Auth panel.
1835 ctrl_settitle(b, "Connection/SSH/Auth",
1836 "Options controlling SSH authentication");
1838 s = ctrl_getset(b, "Connection/SSH/Auth", "main", NULL);
1839 ctrl_checkbox(s, "Bypass authentication entirely (SSH-2 only)", 'b',
1840 HELPCTX(ssh_auth_bypass),
1841 dlg_stdcheckbox_handler,
1842 I(offsetof(Config,ssh_no_userauth)));
1844 s = ctrl_getset(b, "Connection/SSH/Auth", "methods",
1845 "Authentication methods");
1846 ctrl_checkbox(s, "Attempt authentication using Pageant", 'p',
1847 HELPCTX(ssh_auth_pageant),
1848 dlg_stdcheckbox_handler,
1849 I(offsetof(Config,tryagent)));
1850 ctrl_checkbox(s, "Attempt TIS or CryptoCard auth (SSH-1)", 'm',
1851 HELPCTX(ssh_auth_tis),
1852 dlg_stdcheckbox_handler,
1853 I(offsetof(Config,try_tis_auth)));
1854 ctrl_checkbox(s, "Attempt \"keyboard-interactive\" auth (SSH-2)",
1855 'i', HELPCTX(ssh_auth_ki),
1856 dlg_stdcheckbox_handler,
1857 I(offsetof(Config,try_ki_auth)));
1859 s = ctrl_getset(b, "Connection/SSH/Auth", "params",
1860 "Authentication parameters");
1861 ctrl_checkbox(s, "Allow agent forwarding", 'f',
1862 HELPCTX(ssh_auth_agentfwd),
1863 dlg_stdcheckbox_handler, I(offsetof(Config,agentfwd)));
1864 ctrl_checkbox(s, "Allow attempted changes of username in SSH-2", 'u',
1865 HELPCTX(ssh_auth_changeuser),
1866 dlg_stdcheckbox_handler,
1867 I(offsetof(Config,change_username)));
1868 ctrl_filesel(s, "Private key file for authentication:", 'k',
1869 FILTER_KEY_FILES, FALSE, "Select private key file",
1870 HELPCTX(ssh_auth_privkey),
1871 dlg_stdfilesel_handler, I(offsetof(Config, keyfile)));
1876 * The Connection/SSH/TTY panel.
1878 ctrl_settitle(b, "Connection/SSH/TTY", "Remote terminal settings");
1880 s = ctrl_getset(b, "Connection/SSH/TTY", "sshtty", NULL);
1881 ctrl_checkbox(s, "Don't allocate a pseudo-terminal", 'p',
1883 dlg_stdcheckbox_handler,
1884 I(offsetof(Config,nopty)));
1886 s = ctrl_getset(b, "Connection/SSH/TTY", "ttymodes",
1888 td = (struct ttymodes_data *)
1889 ctrl_alloc(b, sizeof(struct ttymodes_data));
1890 ctrl_columns(s, 2, 75, 25);
1891 c = ctrl_text(s, "Terminal modes to send:", HELPCTX(ssh_ttymodes));
1892 c->generic.column = 0;
1893 td->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1894 HELPCTX(ssh_ttymodes),
1895 ttymodes_handler, P(td));
1896 td->rembutton->generic.column = 1;
1897 td->rembutton->generic.tabdelay = 1;
1898 ctrl_columns(s, 1, 100);
1899 td->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1900 HELPCTX(ssh_ttymodes),
1901 ttymodes_handler, P(td));
1902 td->listbox->listbox.multisel = 1;
1903 td->listbox->listbox.height = 4;
1904 td->listbox->listbox.ncols = 2;
1905 td->listbox->listbox.percentages = snewn(2, int);
1906 td->listbox->listbox.percentages[0] = 40;
1907 td->listbox->listbox.percentages[1] = 60;
1908 ctrl_tabdelay(s, td->rembutton);
1909 ctrl_columns(s, 2, 75, 25);
1910 td->modelist = ctrl_droplist(s, "Mode:", 'm', 67,
1911 HELPCTX(ssh_ttymodes),
1912 ttymodes_handler, P(td));
1913 td->modelist->generic.column = 0;
1914 td->addbutton = ctrl_pushbutton(s, "Add", 'd',
1915 HELPCTX(ssh_ttymodes),
1916 ttymodes_handler, P(td));
1917 td->addbutton->generic.column = 1;
1918 td->addbutton->generic.tabdelay = 1;
1919 ctrl_columns(s, 1, 100); /* column break */
1920 /* Bit of a hack to get the value radio buttons and
1921 * edit-box on the same row. */
1922 ctrl_columns(s, 3, 25, 50, 25);
1923 c = ctrl_text(s, "Value:", HELPCTX(ssh_ttymodes));
1924 c->generic.column = 0;
1925 td->valradio = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 2,
1926 HELPCTX(ssh_ttymodes),
1927 ttymodes_handler, P(td),
1928 "Auto", NO_SHORTCUT, P(NULL),
1929 "This:", NO_SHORTCUT, P(NULL),
1931 td->valradio->generic.column = 1;
1932 td->valbox = ctrl_editbox(s, NULL, NO_SHORTCUT, 100,
1933 HELPCTX(ssh_ttymodes),
1934 ttymodes_handler, P(td), P(NULL));
1935 td->valbox->generic.column = 2;
1936 ctrl_tabdelay(s, td->addbutton);
1942 * The Connection/SSH/X11 panel.
1944 ctrl_settitle(b, "Connection/SSH/X11",
1945 "Options controlling SSH X11 forwarding");
1947 s = ctrl_getset(b, "Connection/SSH/X11", "x11", "X11 forwarding");
1948 ctrl_checkbox(s, "Enable X11 forwarding", 'e',
1949 HELPCTX(ssh_tunnels_x11),
1950 dlg_stdcheckbox_handler,I(offsetof(Config,x11_forward)));
1951 ctrl_editbox(s, "X display location", 'x', 50,
1952 HELPCTX(ssh_tunnels_x11),
1953 dlg_stdeditbox_handler, I(offsetof(Config,x11_display)),
1954 I(sizeof(((Config *)0)->x11_display)));
1955 ctrl_radiobuttons(s, "Remote X11 authentication protocol", 'u', 2,
1956 HELPCTX(ssh_tunnels_x11auth),
1957 dlg_stdradiobutton_handler,
1958 I(offsetof(Config, x11_auth)),
1959 "MIT-Magic-Cookie-1", I(X11_MIT),
1960 "XDM-Authorization-1", I(X11_XDM), NULL);
1964 * The Tunnels panel _is_ still available in mid-session.
1966 ctrl_settitle(b, "Connection/SSH/Tunnels",
1967 "Options controlling SSH port forwarding");
1969 s = ctrl_getset(b, "Connection/SSH/Tunnels", "portfwd",
1971 ctrl_checkbox(s, "Local ports accept connections from other hosts",'t',
1972 HELPCTX(ssh_tunnels_portfwd_localhost),
1973 dlg_stdcheckbox_handler,
1974 I(offsetof(Config,lport_acceptall)));
1975 ctrl_checkbox(s, "Remote ports do the same (SSH-2 only)", 'p',
1976 HELPCTX(ssh_tunnels_portfwd_localhost),
1977 dlg_stdcheckbox_handler,
1978 I(offsetof(Config,rport_acceptall)));
1980 ctrl_columns(s, 3, 55, 20, 25);
1981 c = ctrl_text(s, "Forwarded ports:", HELPCTX(ssh_tunnels_portfwd));
1982 c->generic.column = COLUMN_FIELD(0,2);
1983 /* You want to select from the list, _then_ hit Remove. So tab order
1984 * should be that way round. */
1985 pfd = (struct portfwd_data *)ctrl_alloc(b,sizeof(struct portfwd_data));
1986 pfd->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1987 HELPCTX(ssh_tunnels_portfwd),
1988 portfwd_handler, P(pfd));
1989 pfd->rembutton->generic.column = 2;
1990 pfd->rembutton->generic.tabdelay = 1;
1991 pfd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1992 HELPCTX(ssh_tunnels_portfwd),
1993 portfwd_handler, P(pfd));
1994 pfd->listbox->listbox.height = 3;
1995 pfd->listbox->listbox.ncols = 2;
1996 pfd->listbox->listbox.percentages = snewn(2, int);
1997 pfd->listbox->listbox.percentages[0] = 20;
1998 pfd->listbox->listbox.percentages[1] = 80;
1999 ctrl_tabdelay(s, pfd->rembutton);
2000 ctrl_text(s, "Add new forwarded port:", HELPCTX(ssh_tunnels_portfwd));
2001 /* You want to enter source, destination and type, _then_ hit Add.
2002 * Again, we adjust the tab order to reflect this. */
2003 pfd->addbutton = ctrl_pushbutton(s, "Add", 'd',
2004 HELPCTX(ssh_tunnels_portfwd),
2005 portfwd_handler, P(pfd));
2006 pfd->addbutton->generic.column = 2;
2007 pfd->addbutton->generic.tabdelay = 1;
2008 pfd->sourcebox = ctrl_editbox(s, "Source port", 's', 40,
2009 HELPCTX(ssh_tunnels_portfwd),
2010 portfwd_handler, P(pfd), P(NULL));
2011 pfd->sourcebox->generic.column = 0;
2012 pfd->destbox = ctrl_editbox(s, "Destination", 'i', 67,
2013 HELPCTX(ssh_tunnels_portfwd),
2014 portfwd_handler, P(pfd), P(NULL));
2015 pfd->direction = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
2016 HELPCTX(ssh_tunnels_portfwd),
2017 portfwd_handler, P(pfd),
2018 "Local", 'l', P(NULL),
2019 "Remote", 'm', P(NULL),
2020 "Dynamic", 'y', P(NULL),
2023 pfd->addressfamily =
2024 ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
2025 HELPCTX(ssh_tunnels_portfwd_ipversion),
2026 portfwd_handler, P(pfd),
2027 "Auto", 'u', I(ADDRTYPE_UNSPEC),
2028 "IPv4", '4', I(ADDRTYPE_IPV4),
2029 "IPv6", '6', I(ADDRTYPE_IPV6),
2032 ctrl_tabdelay(s, pfd->addbutton);
2033 ctrl_columns(s, 1, 100);
2037 * The Connection/SSH/Bugs panel.
2039 ctrl_settitle(b, "Connection/SSH/Bugs",
2040 "Workarounds for SSH server bugs");
2042 s = ctrl_getset(b, "Connection/SSH/Bugs", "main",
2043 "Detection of known bugs in SSH servers");
2044 ctrl_droplist(s, "Chokes on SSH-1 ignore messages", 'i', 20,
2045 HELPCTX(ssh_bugs_ignore1),
2046 sshbug_handler, I(offsetof(Config,sshbug_ignore1)));
2047 ctrl_droplist(s, "Refuses all SSH-1 password camouflage", 's', 20,
2048 HELPCTX(ssh_bugs_plainpw1),
2049 sshbug_handler, I(offsetof(Config,sshbug_plainpw1)));
2050 ctrl_droplist(s, "Chokes on SSH-1 RSA authentication", 'r', 20,
2051 HELPCTX(ssh_bugs_rsa1),
2052 sshbug_handler, I(offsetof(Config,sshbug_rsa1)));
2053 ctrl_droplist(s, "Miscomputes SSH-2 HMAC keys", 'm', 20,
2054 HELPCTX(ssh_bugs_hmac2),
2055 sshbug_handler, I(offsetof(Config,sshbug_hmac2)));
2056 ctrl_droplist(s, "Miscomputes SSH-2 encryption keys", 'e', 20,
2057 HELPCTX(ssh_bugs_derivekey2),
2058 sshbug_handler, I(offsetof(Config,sshbug_derivekey2)));
2059 ctrl_droplist(s, "Requires padding on SSH-2 RSA signatures", 'p', 20,
2060 HELPCTX(ssh_bugs_rsapad2),
2061 sshbug_handler, I(offsetof(Config,sshbug_rsapad2)));
2062 ctrl_droplist(s, "Misuses the session ID in SSH-2 PK auth", 'n', 20,
2063 HELPCTX(ssh_bugs_pksessid2),
2064 sshbug_handler, I(offsetof(Config,sshbug_pksessid2)));
2065 ctrl_droplist(s, "Handles SSH-2 key re-exchange badly", 'k', 20,
2066 HELPCTX(ssh_bugs_rekey2),
2067 sshbug_handler, I(offsetof(Config,sshbug_rekey2)));