2 * config.c - the platform-independent parts of the PuTTY
13 #define PRINTER_DISABLED_STRING "None (printing disabled)"
15 #define HOST_BOX_TITLE "Host Name (or IP address)"
16 #define PORT_BOX_TITLE "Port"
18 static void config_host_handler(union control *ctrl, void *dlg,
19 void *data, int event)
21 Config *cfg = (Config *)data;
24 * This function works just like the standard edit box handler,
25 * only it has to choose the control's label and text from two
26 * different places depending on the protocol.
28 if (event == EVENT_REFRESH) {
29 if (cfg->protocol == PROT_SERIAL) {
31 * This label text is carefully chosen to contain an n,
32 * since that's the shortcut for the host name control.
34 dlg_label_change(ctrl, dlg, "Serial line");
35 dlg_editbox_set(ctrl, dlg, cfg->serline);
37 dlg_label_change(ctrl, dlg, HOST_BOX_TITLE);
38 dlg_editbox_set(ctrl, dlg, cfg->host);
40 } else if (event == EVENT_VALCHANGE) {
41 if (cfg->protocol == PROT_SERIAL)
42 dlg_editbox_get(ctrl, dlg, cfg->serline, lenof(cfg->serline));
44 dlg_editbox_get(ctrl, dlg, cfg->host, lenof(cfg->host));
48 static void config_port_handler(union control *ctrl, void *dlg,
49 void *data, int event)
51 Config *cfg = (Config *)data;
55 * This function works just like the standard edit box handler,
56 * only it has to choose the control's label and text from two
57 * different places depending on the protocol.
59 if (event == EVENT_REFRESH) {
60 if (cfg->protocol == PROT_SERIAL) {
62 * This label text is carefully chosen to contain a p,
63 * since that's the shortcut for the port control.
65 dlg_label_change(ctrl, dlg, "Speed");
66 sprintf(buf, "%d", cfg->serspeed);
68 dlg_label_change(ctrl, dlg, PORT_BOX_TITLE);
69 sprintf(buf, "%d", cfg->port);
71 dlg_editbox_set(ctrl, dlg, buf);
72 } else if (event == EVENT_VALCHANGE) {
73 dlg_editbox_get(ctrl, dlg, buf, lenof(buf));
74 if (cfg->protocol == PROT_SERIAL)
75 cfg->serspeed = atoi(buf);
77 cfg->port = atoi(buf);
82 union control *host, *port;
86 * We export this function so that platform-specific config
87 * routines can use it to conveniently identify the protocol radio
88 * buttons in order to add to them.
90 void config_protocolbuttons_handler(union control *ctrl, void *dlg,
91 void *data, int event)
94 Config *cfg = (Config *)data;
95 struct hostport *hp = (struct hostport *)ctrl->radio.context.p;
98 * This function works just like the standard radio-button
99 * handler, except that it also has to change the setting of
100 * the port box, and refresh both host and port boxes when. We
101 * expect the context parameter to point at a hostport
102 * structure giving the `union control's for both.
104 if (event == EVENT_REFRESH) {
105 for (button = 0; button < ctrl->radio.nbuttons; button++)
106 if (cfg->protocol == ctrl->radio.buttondata[button].i)
108 /* We expected that `break' to happen, in all circumstances. */
109 assert(button < ctrl->radio.nbuttons);
110 dlg_radiobutton_set(ctrl, dlg, button);
111 } else if (event == EVENT_VALCHANGE) {
112 int oldproto = cfg->protocol;
113 button = dlg_radiobutton_get(ctrl, dlg);
114 assert(button >= 0 && button < ctrl->radio.nbuttons);
115 cfg->protocol = ctrl->radio.buttondata[button].i;
116 if (oldproto != cfg->protocol) {
117 Backend *ob = backend_from_proto(oldproto);
118 Backend *nb = backend_from_proto(cfg->protocol);
121 /* Iff the user hasn't changed the port from the protocol
122 * default (if any), update it with the new protocol's
124 * (XXX: this isn't perfect; a default can become permanent
125 * by going via the serial backend. However, it helps with
126 * the common case of tabbing through the controls in order
127 * and setting a non-default port.) */
128 if (cfg->port == ob->default_port &&
129 cfg->port > 0 && nb->default_port > 0)
130 cfg->port = nb->default_port;
132 dlg_refresh(hp->host, dlg);
133 dlg_refresh(hp->port, dlg);
137 static void loggingbuttons_handler(union control *ctrl, void *dlg,
138 void *data, int event)
141 Config *cfg = (Config *)data;
142 /* This function works just like the standard radio-button handler,
143 * but it has to fall back to "no logging" in situations where the
144 * configured logging type isn't applicable.
146 if (event == EVENT_REFRESH) {
147 for (button = 0; button < ctrl->radio.nbuttons; button++)
148 if (cfg->logtype == ctrl->radio.buttondata[button].i)
151 /* We fell off the end, so we lack the configured logging type */
152 if (button == ctrl->radio.nbuttons) {
154 cfg->logtype=LGTYP_NONE;
156 dlg_radiobutton_set(ctrl, dlg, button);
157 } else if (event == EVENT_VALCHANGE) {
158 button = dlg_radiobutton_get(ctrl, dlg);
159 assert(button >= 0 && button < ctrl->radio.nbuttons);
160 cfg->logtype = ctrl->radio.buttondata[button].i;
164 static void numeric_keypad_handler(union control *ctrl, void *dlg,
165 void *data, int event)
168 Config *cfg = (Config *)data;
170 * This function works much like the standard radio button
171 * handler, but it has to handle two fields in Config.
173 if (event == EVENT_REFRESH) {
174 if (cfg->nethack_keypad)
176 else if (cfg->app_keypad)
180 assert(button < ctrl->radio.nbuttons);
181 dlg_radiobutton_set(ctrl, dlg, button);
182 } else if (event == EVENT_VALCHANGE) {
183 button = dlg_radiobutton_get(ctrl, dlg);
184 assert(button >= 0 && button < ctrl->radio.nbuttons);
186 cfg->app_keypad = FALSE;
187 cfg->nethack_keypad = TRUE;
189 cfg->app_keypad = (button != 0);
190 cfg->nethack_keypad = FALSE;
195 static void cipherlist_handler(union control *ctrl, void *dlg,
196 void *data, int event)
198 Config *cfg = (Config *)data;
199 if (event == EVENT_REFRESH) {
202 static const struct { char *s; int c; } ciphers[] = {
203 { "3DES", CIPHER_3DES },
204 { "Blowfish", CIPHER_BLOWFISH },
205 { "DES", CIPHER_DES },
206 { "AES (SSH-2 only)", CIPHER_AES },
207 { "Arcfour (SSH-2 only)", CIPHER_ARCFOUR },
208 { "-- warn below here --", CIPHER_WARN }
211 /* Set up the "selected ciphers" box. */
212 /* (cipherlist assumed to contain all ciphers) */
213 dlg_update_start(ctrl, dlg);
214 dlg_listbox_clear(ctrl, dlg);
215 for (i = 0; i < CIPHER_MAX; i++) {
216 int c = cfg->ssh_cipherlist[i];
219 for (j = 0; j < (sizeof ciphers) / (sizeof ciphers[0]); j++) {
220 if (ciphers[j].c == c) {
225 dlg_listbox_addwithid(ctrl, dlg, cstr, c);
227 dlg_update_done(ctrl, dlg);
229 } else if (event == EVENT_VALCHANGE) {
232 /* Update array to match the list box. */
233 for (i=0; i < CIPHER_MAX; i++)
234 cfg->ssh_cipherlist[i] = dlg_listbox_getid(ctrl, dlg, i);
239 static void kexlist_handler(union control *ctrl, void *dlg,
240 void *data, int event)
242 Config *cfg = (Config *)data;
243 if (event == EVENT_REFRESH) {
246 static const struct { char *s; int k; } kexes[] = {
247 { "Diffie-Hellman group 1", KEX_DHGROUP1 },
248 { "Diffie-Hellman group 14", KEX_DHGROUP14 },
249 { "Diffie-Hellman group exchange", KEX_DHGEX },
250 { "RSA-based key exchange", KEX_RSA },
251 { "-- warn below here --", KEX_WARN }
254 /* Set up the "kex preference" box. */
255 /* (kexlist assumed to contain all algorithms) */
256 dlg_update_start(ctrl, dlg);
257 dlg_listbox_clear(ctrl, dlg);
258 for (i = 0; i < KEX_MAX; i++) {
259 int k = cfg->ssh_kexlist[i];
262 for (j = 0; j < (sizeof kexes) / (sizeof kexes[0]); j++) {
263 if (kexes[j].k == k) {
268 dlg_listbox_addwithid(ctrl, dlg, kstr, k);
270 dlg_update_done(ctrl, dlg);
272 } else if (event == EVENT_VALCHANGE) {
275 /* Update array to match the list box. */
276 for (i=0; i < KEX_MAX; i++)
277 cfg->ssh_kexlist[i] = dlg_listbox_getid(ctrl, dlg, i);
282 static void printerbox_handler(union control *ctrl, void *dlg,
283 void *data, int event)
285 Config *cfg = (Config *)data;
286 if (event == EVENT_REFRESH) {
290 dlg_update_start(ctrl, dlg);
292 * Some backends may wish to disable the drop-down list on
293 * this edit box. Be prepared for this.
295 if (ctrl->editbox.has_list) {
296 dlg_listbox_clear(ctrl, dlg);
297 dlg_listbox_add(ctrl, dlg, PRINTER_DISABLED_STRING);
298 pe = printer_start_enum(&nprinters);
299 for (i = 0; i < nprinters; i++)
300 dlg_listbox_add(ctrl, dlg, printer_get_name(pe, i));
301 printer_finish_enum(pe);
303 dlg_editbox_set(ctrl, dlg,
304 (*cfg->printer ? cfg->printer :
305 PRINTER_DISABLED_STRING));
306 dlg_update_done(ctrl, dlg);
307 } else if (event == EVENT_VALCHANGE) {
308 dlg_editbox_get(ctrl, dlg, cfg->printer, sizeof(cfg->printer));
309 if (!strcmp(cfg->printer, PRINTER_DISABLED_STRING))
310 *cfg->printer = '\0';
314 static void codepage_handler(union control *ctrl, void *dlg,
315 void *data, int event)
317 Config *cfg = (Config *)data;
318 if (event == EVENT_REFRESH) {
321 dlg_update_start(ctrl, dlg);
322 strcpy(cfg->line_codepage,
323 cp_name(decode_codepage(cfg->line_codepage)));
324 dlg_listbox_clear(ctrl, dlg);
325 for (i = 0; (cp = cp_enumerate(i)) != NULL; i++)
326 dlg_listbox_add(ctrl, dlg, cp);
327 dlg_editbox_set(ctrl, dlg, cfg->line_codepage);
328 dlg_update_done(ctrl, dlg);
329 } else if (event == EVENT_VALCHANGE) {
330 dlg_editbox_get(ctrl, dlg, cfg->line_codepage,
331 sizeof(cfg->line_codepage));
332 strcpy(cfg->line_codepage,
333 cp_name(decode_codepage(cfg->line_codepage)));
337 static void sshbug_handler(union control *ctrl, void *dlg,
338 void *data, int event)
340 if (event == EVENT_REFRESH) {
341 dlg_update_start(ctrl, dlg);
342 dlg_listbox_clear(ctrl, dlg);
343 dlg_listbox_addwithid(ctrl, dlg, "Auto", AUTO);
344 dlg_listbox_addwithid(ctrl, dlg, "Off", FORCE_OFF);
345 dlg_listbox_addwithid(ctrl, dlg, "On", FORCE_ON);
346 switch (*(int *)ATOFFSET(data, ctrl->listbox.context.i)) {
347 case AUTO: dlg_listbox_select(ctrl, dlg, 0); break;
348 case FORCE_OFF: dlg_listbox_select(ctrl, dlg, 1); break;
349 case FORCE_ON: dlg_listbox_select(ctrl, dlg, 2); break;
351 dlg_update_done(ctrl, dlg);
352 } else if (event == EVENT_SELCHANGE) {
353 int i = dlg_listbox_index(ctrl, dlg);
357 i = dlg_listbox_getid(ctrl, dlg, i);
358 *(int *)ATOFFSET(data, ctrl->listbox.context.i) = i;
362 #define SAVEDSESSION_LEN 2048
364 struct sessionsaver_data {
365 union control *editbox, *listbox, *loadbutton, *savebutton, *delbutton;
366 union control *okbutton, *cancelbutton;
367 struct sesslist sesslist;
372 * Helper function to load the session selected in the list box, if
373 * any, as this is done in more than one place below. Returns 0 for
376 static int load_selected_session(struct sessionsaver_data *ssd,
378 void *dlg, Config *cfg, int *maybe_launch)
380 int i = dlg_listbox_index(ssd->listbox, dlg);
386 isdef = !strcmp(ssd->sesslist.sessions[i], "Default Settings");
387 load_settings(ssd->sesslist.sessions[i], cfg);
389 strncpy(savedsession, ssd->sesslist.sessions[i],
391 savedsession[SAVEDSESSION_LEN-1] = '\0';
393 *maybe_launch = TRUE;
395 savedsession[0] = '\0';
397 *maybe_launch = FALSE;
399 dlg_refresh(NULL, dlg);
400 /* Restore the selection, which might have been clobbered by
401 * changing the value of the edit box. */
402 dlg_listbox_select(ssd->listbox, dlg, i);
406 static void sessionsaver_handler(union control *ctrl, void *dlg,
407 void *data, int event)
409 Config *cfg = (Config *)data;
410 struct sessionsaver_data *ssd =
411 (struct sessionsaver_data *)ctrl->generic.context.p;
415 * The first time we're called in a new dialog, we must
416 * allocate space to store the current contents of the saved
417 * session edit box (since it must persist even when we switch
418 * panels, but is not part of the Config).
422 } else if (!dlg_get_privdata(ssd->editbox, dlg)) {
423 savedsession = (char *)
424 dlg_alloc_privdata(ssd->editbox, dlg, SAVEDSESSION_LEN);
425 savedsession[0] = '\0';
427 savedsession = dlg_get_privdata(ssd->editbox, dlg);
430 if (event == EVENT_REFRESH) {
431 if (ctrl == ssd->editbox) {
432 dlg_editbox_set(ctrl, dlg, savedsession);
433 } else if (ctrl == ssd->listbox) {
435 dlg_update_start(ctrl, dlg);
436 dlg_listbox_clear(ctrl, dlg);
437 for (i = 0; i < ssd->sesslist.nsessions; i++)
438 dlg_listbox_add(ctrl, dlg, ssd->sesslist.sessions[i]);
439 dlg_update_done(ctrl, dlg);
441 } else if (event == EVENT_VALCHANGE) {
442 int top, bottom, halfway, i;
443 if (ctrl == ssd->editbox) {
444 dlg_editbox_get(ctrl, dlg, savedsession,
446 top = ssd->sesslist.nsessions;
448 while (top-bottom > 1) {
449 halfway = (top+bottom)/2;
450 i = strcmp(savedsession, ssd->sesslist.sessions[halfway]);
457 if (top == ssd->sesslist.nsessions) {
460 dlg_listbox_select(ssd->listbox, dlg, top);
462 } else if (event == EVENT_ACTION) {
464 if (!ssd->midsession &&
465 (ctrl == ssd->listbox ||
466 (ssd->loadbutton && ctrl == ssd->loadbutton))) {
468 * The user has double-clicked a session, or hit Load.
469 * We must load the selected session, and then
470 * terminate the configuration dialog _if_ there was a
471 * double-click on the list box _and_ that session
472 * contains a hostname.
474 if (load_selected_session(ssd, savedsession, dlg, cfg, &mbl) &&
475 (mbl && ctrl == ssd->listbox && cfg_launchable(cfg))) {
476 dlg_end(dlg, 1); /* it's all over, and succeeded */
478 } else if (ctrl == ssd->savebutton) {
479 int isdef = !strcmp(savedsession, "Default Settings");
480 if (!savedsession[0]) {
481 int i = dlg_listbox_index(ssd->listbox, dlg);
486 isdef = !strcmp(ssd->sesslist.sessions[i], "Default Settings");
488 strncpy(savedsession, ssd->sesslist.sessions[i],
490 savedsession[SAVEDSESSION_LEN-1] = '\0';
492 savedsession[0] = '\0';
496 char *errmsg = save_settings(savedsession, cfg);
498 dlg_error_msg(dlg, errmsg);
502 get_sesslist(&ssd->sesslist, FALSE);
503 get_sesslist(&ssd->sesslist, TRUE);
504 dlg_refresh(ssd->editbox, dlg);
505 dlg_refresh(ssd->listbox, dlg);
506 } else if (!ssd->midsession &&
507 ssd->delbutton && ctrl == ssd->delbutton) {
508 int i = dlg_listbox_index(ssd->listbox, dlg);
512 del_settings(ssd->sesslist.sessions[i]);
513 get_sesslist(&ssd->sesslist, FALSE);
514 get_sesslist(&ssd->sesslist, TRUE);
515 dlg_refresh(ssd->listbox, dlg);
517 } else if (ctrl == ssd->okbutton) {
518 if (ssd->midsession) {
519 /* In a mid-session Change Settings, Apply is always OK. */
524 * Annoying special case. If the `Open' button is
525 * pressed while no host name is currently set, _and_
526 * the session list previously had the focus, _and_
527 * there was a session selected in that which had a
528 * valid host name in it, then load it and go.
530 if (dlg_last_focused(ctrl, dlg) == ssd->listbox &&
531 !cfg_launchable(cfg)) {
534 if (!load_selected_session(ssd, savedsession, dlg,
539 /* If at this point we have a valid session, go! */
540 if (mbl && cfg_launchable(&cfg2)) {
541 *cfg = cfg2; /* structure copy */
542 cfg->remote_cmd_ptr = NULL;
550 * Otherwise, do the normal thing: if we have a valid
551 * session, get going.
553 if (cfg_launchable(cfg)) {
557 } else if (ctrl == ssd->cancelbutton) {
563 struct charclass_data {
564 union control *listbox, *editbox, *button;
567 static void charclass_handler(union control *ctrl, void *dlg,
568 void *data, int event)
570 Config *cfg = (Config *)data;
571 struct charclass_data *ccd =
572 (struct charclass_data *)ctrl->generic.context.p;
574 if (event == EVENT_REFRESH) {
575 if (ctrl == ccd->listbox) {
577 dlg_update_start(ctrl, dlg);
578 dlg_listbox_clear(ctrl, dlg);
579 for (i = 0; i < 128; i++) {
581 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
582 (i >= 0x21 && i != 0x7F) ? i : ' ', cfg->wordness[i]);
583 dlg_listbox_add(ctrl, dlg, str);
585 dlg_update_done(ctrl, dlg);
587 } else if (event == EVENT_ACTION) {
588 if (ctrl == ccd->button) {
591 dlg_editbox_get(ccd->editbox, dlg, str, sizeof(str));
593 for (i = 0; i < 128; i++) {
594 if (dlg_listbox_issel(ccd->listbox, dlg, i))
595 cfg->wordness[i] = n;
597 dlg_refresh(ccd->listbox, dlg);
603 union control *listbox, *redit, *gedit, *bedit, *button;
606 static const char *const colours[] = {
607 "Default Foreground", "Default Bold Foreground",
608 "Default Background", "Default Bold Background",
609 "Cursor Text", "Cursor Colour",
610 "ANSI Black", "ANSI Black Bold",
611 "ANSI Red", "ANSI Red Bold",
612 "ANSI Green", "ANSI Green Bold",
613 "ANSI Yellow", "ANSI Yellow Bold",
614 "ANSI Blue", "ANSI Blue Bold",
615 "ANSI Magenta", "ANSI Magenta Bold",
616 "ANSI Cyan", "ANSI Cyan Bold",
617 "ANSI White", "ANSI White Bold"
620 static void colour_handler(union control *ctrl, void *dlg,
621 void *data, int event)
623 Config *cfg = (Config *)data;
624 struct colour_data *cd =
625 (struct colour_data *)ctrl->generic.context.p;
626 int update = FALSE, r, g, b;
628 if (event == EVENT_REFRESH) {
629 if (ctrl == cd->listbox) {
631 dlg_update_start(ctrl, dlg);
632 dlg_listbox_clear(ctrl, dlg);
633 for (i = 0; i < lenof(colours); i++)
634 dlg_listbox_add(ctrl, dlg, colours[i]);
635 dlg_update_done(ctrl, dlg);
636 dlg_editbox_set(cd->redit, dlg, "");
637 dlg_editbox_set(cd->gedit, dlg, "");
638 dlg_editbox_set(cd->bedit, dlg, "");
640 } else if (event == EVENT_SELCHANGE) {
641 if (ctrl == cd->listbox) {
642 /* The user has selected a colour. Update the RGB text. */
643 int i = dlg_listbox_index(ctrl, dlg);
648 r = cfg->colours[i][0];
649 g = cfg->colours[i][1];
650 b = cfg->colours[i][2];
653 } else if (event == EVENT_VALCHANGE) {
654 if (ctrl == cd->redit || ctrl == cd->gedit || ctrl == cd->bedit) {
655 /* The user has changed the colour using the edit boxes. */
659 dlg_editbox_get(ctrl, dlg, buf, lenof(buf));
661 if (cval > 255) cval = 255;
662 if (cval < 0) cval = 0;
664 i = dlg_listbox_index(cd->listbox, dlg);
666 if (ctrl == cd->redit)
667 cfg->colours[i][0] = cval;
668 else if (ctrl == cd->gedit)
669 cfg->colours[i][1] = cval;
670 else if (ctrl == cd->bedit)
671 cfg->colours[i][2] = cval;
674 } else if (event == EVENT_ACTION) {
675 if (ctrl == cd->button) {
676 int i = dlg_listbox_index(cd->listbox, dlg);
682 * Start a colour selector, which will send us an
683 * EVENT_CALLBACK when it's finished and allow us to
684 * pick up the results.
686 dlg_coloursel_start(ctrl, dlg,
691 } else if (event == EVENT_CALLBACK) {
692 if (ctrl == cd->button) {
693 int i = dlg_listbox_index(cd->listbox, dlg);
695 * Collect the results of the colour selector. Will
696 * return nonzero on success, or zero if the colour
697 * selector did nothing (user hit Cancel, for example).
699 if (dlg_coloursel_results(ctrl, dlg, &r, &g, &b)) {
700 cfg->colours[i][0] = r;
701 cfg->colours[i][1] = g;
702 cfg->colours[i][2] = b;
710 sprintf(buf, "%d", r); dlg_editbox_set(cd->redit, dlg, buf);
711 sprintf(buf, "%d", g); dlg_editbox_set(cd->gedit, dlg, buf);
712 sprintf(buf, "%d", b); dlg_editbox_set(cd->bedit, dlg, buf);
716 struct ttymodes_data {
717 union control *modelist, *valradio, *valbox;
718 union control *addbutton, *rembutton, *listbox;
721 static void ttymodes_handler(union control *ctrl, void *dlg,
722 void *data, int event)
724 Config *cfg = (Config *)data;
725 struct ttymodes_data *td =
726 (struct ttymodes_data *)ctrl->generic.context.p;
728 if (event == EVENT_REFRESH) {
729 if (ctrl == td->listbox) {
730 char *p = cfg->ttymodes;
731 dlg_update_start(ctrl, dlg);
732 dlg_listbox_clear(ctrl, dlg);
734 int tabpos = strchr(p, '\t') - p;
735 char *disp = dupprintf("%.*s\t%s", tabpos, p,
736 (p[tabpos+1] == 'A') ? "(auto)" :
738 dlg_listbox_add(ctrl, dlg, disp);
742 dlg_update_done(ctrl, dlg);
743 } else if (ctrl == td->modelist) {
745 dlg_update_start(ctrl, dlg);
746 dlg_listbox_clear(ctrl, dlg);
747 for (i = 0; ttymodes[i]; i++)
748 dlg_listbox_add(ctrl, dlg, ttymodes[i]);
749 dlg_listbox_select(ctrl, dlg, 0); /* *shrug* */
750 dlg_update_done(ctrl, dlg);
751 } else if (ctrl == td->valradio) {
752 dlg_radiobutton_set(ctrl, dlg, 0);
754 } else if (event == EVENT_ACTION) {
755 if (ctrl == td->addbutton) {
756 int ind = dlg_listbox_index(td->modelist, dlg);
758 char type = dlg_radiobutton_get(td->valradio, dlg) ? 'V' : 'A';
760 char *p, str[lenof(cfg->ttymodes)];
761 /* Construct new entry */
762 memset(str, 0, lenof(str));
763 strncpy(str, ttymodes[ind], lenof(str)-3);
769 dlg_editbox_get(td->valbox, dlg, str+slen, lenof(str)-slen);
771 /* Find end of list, deleting any existing instance */
773 left = lenof(cfg->ttymodes);
775 int t = strchr(p, '\t') - p;
776 if (t == strlen(ttymodes[ind]) &&
777 strncmp(p, ttymodes[ind], t) == 0) {
778 memmove(p, p+strlen(p)+1, left - (strlen(p)+1));
781 left -= strlen(p) + 1;
784 /* Append new entry */
786 strncpy(p, str, left - 2);
787 dlg_refresh(td->listbox, dlg);
790 } else if (ctrl == td->rembutton) {
791 char *p = cfg->ttymodes;
792 int i = 0, len = lenof(cfg->ttymodes);
794 int multisel = dlg_listbox_index(td->listbox, dlg) < 0;
795 if (dlg_listbox_issel(td->listbox, dlg, i)) {
797 /* Populate controls with entry we're about to
798 * delete, for ease of editing.
799 * (If multiple entries were selected, don't
800 * touch the controls.) */
801 char *val = strchr(p, '\t');
805 while (ttymodes[ind]) {
806 if (strlen(ttymodes[ind]) == val-p-1 &&
807 !strncmp(ttymodes[ind], p, val-p-1))
811 dlg_listbox_select(td->modelist, dlg, ind);
812 dlg_radiobutton_set(td->valradio, dlg,
814 dlg_editbox_set(td->valbox, dlg, val+1);
817 memmove(p, p+strlen(p)+1, len - (strlen(p)+1));
821 len -= strlen(p) + 1;
825 memset(p, 0, lenof(cfg->ttymodes) - len);
826 dlg_refresh(td->listbox, dlg);
831 struct environ_data {
832 union control *varbox, *valbox, *addbutton, *rembutton, *listbox;
835 static void environ_handler(union control *ctrl, void *dlg,
836 void *data, int event)
838 Config *cfg = (Config *)data;
839 struct environ_data *ed =
840 (struct environ_data *)ctrl->generic.context.p;
842 if (event == EVENT_REFRESH) {
843 if (ctrl == ed->listbox) {
844 char *p = cfg->environmt;
845 dlg_update_start(ctrl, dlg);
846 dlg_listbox_clear(ctrl, dlg);
848 dlg_listbox_add(ctrl, dlg, p);
851 dlg_update_done(ctrl, dlg);
853 } else if (event == EVENT_ACTION) {
854 if (ctrl == ed->addbutton) {
855 char str[sizeof(cfg->environmt)];
857 dlg_editbox_get(ed->varbox, dlg, str, sizeof(str)-1);
862 p = str + strlen(str);
864 dlg_editbox_get(ed->valbox, dlg, p, sizeof(str)-1 - (p - str));
875 if ((p - cfg->environmt) + strlen(str) + 2 <
876 sizeof(cfg->environmt)) {
878 p[strlen(str) + 1] = '\0';
879 dlg_listbox_add(ed->listbox, dlg, str);
880 dlg_editbox_set(ed->varbox, dlg, "");
881 dlg_editbox_set(ed->valbox, dlg, "");
883 dlg_error_msg(dlg, "Environment too big");
885 } else if (ctrl == ed->rembutton) {
886 int i = dlg_listbox_index(ed->listbox, dlg);
892 dlg_listbox_del(ed->listbox, dlg, i);
905 /* Populate controls with the entry we're about to delete
906 * for ease of editing */
912 dlg_editbox_set(ed->varbox, dlg, str);
915 dlg_editbox_set(ed->valbox, dlg, str);
932 struct portfwd_data {
933 union control *addbutton, *rembutton, *listbox;
934 union control *sourcebox, *destbox, *direction;
936 union control *addressfamily;
940 static void portfwd_handler(union control *ctrl, void *dlg,
941 void *data, int event)
943 Config *cfg = (Config *)data;
944 struct portfwd_data *pfd =
945 (struct portfwd_data *)ctrl->generic.context.p;
947 if (event == EVENT_REFRESH) {
948 if (ctrl == pfd->listbox) {
949 char *p = cfg->portfwd;
950 dlg_update_start(ctrl, dlg);
951 dlg_listbox_clear(ctrl, dlg);
953 dlg_listbox_add(ctrl, dlg, p);
956 dlg_update_done(ctrl, dlg);
957 } else if (ctrl == pfd->direction) {
961 dlg_radiobutton_set(ctrl, dlg, 0);
963 } else if (ctrl == pfd->addressfamily) {
964 dlg_radiobutton_set(ctrl, dlg, 0);
967 } else if (event == EVENT_ACTION) {
968 if (ctrl == pfd->addbutton) {
969 char str[sizeof(cfg->portfwd)];
976 whichbutton = dlg_radiobutton_get(pfd->addressfamily, dlg);
977 if (whichbutton == 1)
979 else if (whichbutton == 2)
983 whichbutton = dlg_radiobutton_get(pfd->direction, dlg);
984 if (whichbutton == 0)
986 else if (whichbutton == 1)
992 dlg_editbox_get(pfd->sourcebox, dlg, str+i, sizeof(str) - i);
994 dlg_error_msg(dlg, "You need to specify a source port number");
997 p = str + strlen(str);
1000 dlg_editbox_get(pfd->destbox, dlg, p,
1001 sizeof(str) - (p - str));
1002 if (!*p || !strchr(p, ':')) {
1004 "You need to specify a destination address\n"
1005 "in the form \"host.name:port\"");
1016 if ((p - cfg->portfwd) + strlen(str) + 2 <=
1017 sizeof(cfg->portfwd)) {
1019 p[strlen(str) + 1] = '\0';
1020 dlg_listbox_add(pfd->listbox, dlg, str);
1021 dlg_editbox_set(pfd->sourcebox, dlg, "");
1022 dlg_editbox_set(pfd->destbox, dlg, "");
1024 dlg_error_msg(dlg, "Too many forwardings");
1026 } else if (ctrl == pfd->rembutton) {
1027 int i = dlg_listbox_index(pfd->listbox, dlg);
1031 char *p, *q, *src, *dst;
1034 dlg_listbox_del(pfd->listbox, dlg, i);
1047 /* Populate the controls with the entry we're about to
1048 * delete, for ease of editing. */
1050 static const char *const afs = "A46";
1051 char *afp = strchr(afs, *p);
1053 int idx = afp ? afp-afs : 0;
1058 dlg_radiobutton_set(pfd->addressfamily, dlg, idx);
1062 static const char *const dirs = "LRD";
1064 dlg_radiobutton_set(pfd->direction, dlg,
1065 strchr(dirs, dir) - dirs);
1070 p = strchr(p, '\t');
1080 p = strchr(p, '\0');
1083 dlg_editbox_set(pfd->sourcebox, dlg, src);
1084 dlg_editbox_set(pfd->destbox, dlg, dst);
1098 void setup_config_box(struct controlbox *b, int midsession,
1099 int protocol, int protcfginfo)
1101 struct controlset *s;
1102 struct sessionsaver_data *ssd;
1103 struct charclass_data *ccd;
1104 struct colour_data *cd;
1105 struct ttymodes_data *td;
1106 struct environ_data *ed;
1107 struct portfwd_data *pfd;
1111 ssd = (struct sessionsaver_data *)
1112 ctrl_alloc(b, sizeof(struct sessionsaver_data));
1113 memset(ssd, 0, sizeof(*ssd));
1114 ssd->midsession = midsession;
1117 * The standard panel that appears at the bottom of all panels:
1118 * Open, Cancel, Apply etc.
1120 s = ctrl_getset(b, "", "", "");
1121 ctrl_columns(s, 5, 20, 20, 20, 20, 20);
1122 ssd->okbutton = ctrl_pushbutton(s,
1123 (midsession ? "Apply" : "Open"),
1124 (char)(midsession ? 'a' : 'o'),
1126 sessionsaver_handler, P(ssd));
1127 ssd->okbutton->button.isdefault = TRUE;
1128 ssd->okbutton->generic.column = 3;
1129 ssd->cancelbutton = ctrl_pushbutton(s, "Cancel", 'c', HELPCTX(no_help),
1130 sessionsaver_handler, P(ssd));
1131 ssd->cancelbutton->button.iscancel = TRUE;
1132 ssd->cancelbutton->generic.column = 4;
1133 /* We carefully don't close the 5-column part, so that platform-
1134 * specific add-ons can put extra buttons alongside Open and Cancel. */
1137 * The Session panel.
1139 str = dupprintf("Basic options for your %s session", appname);
1140 ctrl_settitle(b, "Session", str);
1144 struct hostport *hp = (struct hostport *)
1145 ctrl_alloc(b, sizeof(struct hostport));
1147 s = ctrl_getset(b, "Session", "hostport",
1148 "Specify the destination you want to connect to");
1149 ctrl_columns(s, 2, 75, 25);
1150 c = ctrl_editbox(s, HOST_BOX_TITLE, 'n', 100,
1151 HELPCTX(session_hostname),
1152 config_host_handler, I(0), I(0));
1153 c->generic.column = 0;
1155 c = ctrl_editbox(s, PORT_BOX_TITLE, 'p', 100,
1156 HELPCTX(session_hostname),
1157 config_port_handler, I(0), I(0));
1158 c->generic.column = 1;
1160 ctrl_columns(s, 1, 100);
1162 if (!backend_from_proto(PROT_SSH)) {
1163 ctrl_radiobuttons(s, "Connection type:", NO_SHORTCUT, 3,
1164 HELPCTX(session_hostname),
1165 config_protocolbuttons_handler, P(hp),
1166 "Raw", 'r', I(PROT_RAW),
1167 "Telnet", 't', I(PROT_TELNET),
1168 "Rlogin", 'i', I(PROT_RLOGIN),
1171 ctrl_radiobuttons(s, "Connection type:", NO_SHORTCUT, 4,
1172 HELPCTX(session_hostname),
1173 config_protocolbuttons_handler, P(hp),
1174 "Raw", 'r', I(PROT_RAW),
1175 "Telnet", 't', I(PROT_TELNET),
1176 "Rlogin", 'i', I(PROT_RLOGIN),
1177 "SSH", 's', I(PROT_SSH),
1183 * The Load/Save panel is available even in mid-session.
1185 s = ctrl_getset(b, "Session", "savedsessions",
1186 midsession ? "Save the current session settings" :
1187 "Load, save or delete a stored session");
1188 ctrl_columns(s, 2, 75, 25);
1189 get_sesslist(&ssd->sesslist, TRUE);
1190 ssd->editbox = ctrl_editbox(s, "Saved Sessions", 'e', 100,
1191 HELPCTX(session_saved),
1192 sessionsaver_handler, P(ssd), P(NULL));
1193 ssd->editbox->generic.column = 0;
1194 /* Reset columns so that the buttons are alongside the list, rather
1195 * than alongside that edit box. */
1196 ctrl_columns(s, 1, 100);
1197 ctrl_columns(s, 2, 75, 25);
1198 ssd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1199 HELPCTX(session_saved),
1200 sessionsaver_handler, P(ssd));
1201 ssd->listbox->generic.column = 0;
1202 ssd->listbox->listbox.height = 7;
1204 ssd->loadbutton = ctrl_pushbutton(s, "Load", 'l',
1205 HELPCTX(session_saved),
1206 sessionsaver_handler, P(ssd));
1207 ssd->loadbutton->generic.column = 1;
1209 /* We can't offer the Load button mid-session, as it would allow the
1210 * user to load and subsequently save settings they can't see. (And
1211 * also change otherwise immutable settings underfoot; that probably
1212 * shouldn't be a problem, but.) */
1213 ssd->loadbutton = NULL;
1215 /* "Save" button is permitted mid-session. */
1216 ssd->savebutton = ctrl_pushbutton(s, "Save", 'v',
1217 HELPCTX(session_saved),
1218 sessionsaver_handler, P(ssd));
1219 ssd->savebutton->generic.column = 1;
1221 ssd->delbutton = ctrl_pushbutton(s, "Delete", 'd',
1222 HELPCTX(session_saved),
1223 sessionsaver_handler, P(ssd));
1224 ssd->delbutton->generic.column = 1;
1226 /* Disable the Delete button mid-session too, for UI consistency. */
1227 ssd->delbutton = NULL;
1229 ctrl_columns(s, 1, 100);
1231 s = ctrl_getset(b, "Session", "otheropts", NULL);
1232 c = ctrl_radiobuttons(s, "Close window on exit:", 'w', 4,
1233 HELPCTX(session_coe),
1234 dlg_stdradiobutton_handler,
1235 I(offsetof(Config, close_on_exit)),
1236 "Always", I(FORCE_ON),
1237 "Never", I(FORCE_OFF),
1238 "Only on clean exit", I(AUTO), NULL);
1241 * The Session/Logging panel.
1243 ctrl_settitle(b, "Session/Logging", "Options controlling session logging");
1245 s = ctrl_getset(b, "Session/Logging", "main", NULL);
1247 * The logging buttons change depending on whether SSH packet
1248 * logging can sensibly be available.
1251 char *sshlogname, *sshrawlogname;
1252 if ((midsession && protocol == PROT_SSH) ||
1253 (!midsession && backend_from_proto(PROT_SSH))) {
1254 sshlogname = "SSH packets";
1255 sshrawlogname = "SSH packets and raw data";
1257 sshlogname = NULL; /* this will disable both buttons */
1258 sshrawlogname = NULL; /* this will just placate optimisers */
1260 ctrl_radiobuttons(s, "Session logging:", NO_SHORTCUT, 2,
1261 HELPCTX(logging_main),
1262 loggingbuttons_handler,
1263 I(offsetof(Config, logtype)),
1264 "None", 't', I(LGTYP_NONE),
1265 "Printable output", 'p', I(LGTYP_ASCII),
1266 "All session output", 'l', I(LGTYP_DEBUG),
1267 sshlogname, 's', I(LGTYP_PACKETS),
1268 sshrawlogname, 'r', I(LGTYP_SSHRAW),
1271 ctrl_filesel(s, "Log file name:", 'f',
1272 NULL, TRUE, "Select session log file name",
1273 HELPCTX(logging_filename),
1274 dlg_stdfilesel_handler, I(offsetof(Config, logfilename)));
1275 ctrl_text(s, "(Log file name can contain &Y, &M, &D for date,"
1276 " &T for time, and &H for host name)",
1277 HELPCTX(logging_filename));
1278 ctrl_radiobuttons(s, "What to do if the log file already exists:", 'e', 1,
1279 HELPCTX(logging_exists),
1280 dlg_stdradiobutton_handler, I(offsetof(Config,logxfovr)),
1281 "Always overwrite it", I(LGXF_OVR),
1282 "Always append to the end of it", I(LGXF_APN),
1283 "Ask the user every time", I(LGXF_ASK), NULL);
1284 ctrl_checkbox(s, "Flush log file frequently", 'u',
1285 HELPCTX(logging_flush),
1286 dlg_stdcheckbox_handler, I(offsetof(Config,logflush)));
1288 if ((midsession && protocol == PROT_SSH) ||
1289 (!midsession && backend_from_proto(PROT_SSH))) {
1290 s = ctrl_getset(b, "Session/Logging", "ssh",
1291 "Options specific to SSH packet logging");
1292 ctrl_checkbox(s, "Omit known password fields", 'k',
1293 HELPCTX(logging_ssh_omit_password),
1294 dlg_stdcheckbox_handler, I(offsetof(Config,logomitpass)));
1295 ctrl_checkbox(s, "Omit session data", 'd',
1296 HELPCTX(logging_ssh_omit_data),
1297 dlg_stdcheckbox_handler, I(offsetof(Config,logomitdata)));
1301 * The Terminal panel.
1303 ctrl_settitle(b, "Terminal", "Options controlling the terminal emulation");
1305 s = ctrl_getset(b, "Terminal", "general", "Set various terminal options");
1306 ctrl_checkbox(s, "Auto wrap mode initially on", 'w',
1307 HELPCTX(terminal_autowrap),
1308 dlg_stdcheckbox_handler, I(offsetof(Config,wrap_mode)));
1309 ctrl_checkbox(s, "DEC Origin Mode initially on", 'd',
1310 HELPCTX(terminal_decom),
1311 dlg_stdcheckbox_handler, I(offsetof(Config,dec_om)));
1312 ctrl_checkbox(s, "Implicit CR in every LF", 'r',
1313 HELPCTX(terminal_lfhascr),
1314 dlg_stdcheckbox_handler, I(offsetof(Config,lfhascr)));
1315 ctrl_checkbox(s, "Implicit LF in every CR", 'f',
1316 HELPCTX(terminal_crhaslf),
1317 dlg_stdcheckbox_handler, I(offsetof(Config,crhaslf)));
1318 ctrl_checkbox(s, "Use background colour to erase screen", 'e',
1319 HELPCTX(terminal_bce),
1320 dlg_stdcheckbox_handler, I(offsetof(Config,bce)));
1321 ctrl_checkbox(s, "Enable blinking text", 'n',
1322 HELPCTX(terminal_blink),
1323 dlg_stdcheckbox_handler, I(offsetof(Config,blinktext)));
1324 ctrl_editbox(s, "Answerback to ^E:", 's', 100,
1325 HELPCTX(terminal_answerback),
1326 dlg_stdeditbox_handler, I(offsetof(Config,answerback)),
1327 I(sizeof(((Config *)0)->answerback)));
1329 s = ctrl_getset(b, "Terminal", "ldisc", "Line discipline options");
1330 ctrl_radiobuttons(s, "Local echo:", 'l', 3,
1331 HELPCTX(terminal_localecho),
1332 dlg_stdradiobutton_handler,I(offsetof(Config,localecho)),
1334 "Force on", I(FORCE_ON),
1335 "Force off", I(FORCE_OFF), NULL);
1336 ctrl_radiobuttons(s, "Local line editing:", 't', 3,
1337 HELPCTX(terminal_localedit),
1338 dlg_stdradiobutton_handler,I(offsetof(Config,localedit)),
1340 "Force on", I(FORCE_ON),
1341 "Force off", I(FORCE_OFF), NULL);
1343 s = ctrl_getset(b, "Terminal", "printing", "Remote-controlled printing");
1344 ctrl_combobox(s, "Printer to send ANSI printer output to:", 'p', 100,
1345 HELPCTX(terminal_printing),
1346 printerbox_handler, P(NULL), P(NULL));
1349 * The Terminal/Keyboard panel.
1351 ctrl_settitle(b, "Terminal/Keyboard",
1352 "Options controlling the effects of keys");
1354 s = ctrl_getset(b, "Terminal/Keyboard", "mappings",
1355 "Change the sequences sent by:");
1356 ctrl_radiobuttons(s, "The Backspace key", 'b', 2,
1357 HELPCTX(keyboard_backspace),
1358 dlg_stdradiobutton_handler,
1359 I(offsetof(Config, bksp_is_delete)),
1360 "Control-H", I(0), "Control-? (127)", I(1), NULL);
1361 ctrl_radiobuttons(s, "The Home and End keys", 'e', 2,
1362 HELPCTX(keyboard_homeend),
1363 dlg_stdradiobutton_handler,
1364 I(offsetof(Config, rxvt_homeend)),
1365 "Standard", I(0), "rxvt", I(1), NULL);
1366 ctrl_radiobuttons(s, "The Function keys and keypad", 'f', 3,
1367 HELPCTX(keyboard_funkeys),
1368 dlg_stdradiobutton_handler,
1369 I(offsetof(Config, funky_type)),
1370 "ESC[n~", I(0), "Linux", I(1), "Xterm R6", I(2),
1371 "VT400", I(3), "VT100+", I(4), "SCO", I(5), NULL);
1373 s = ctrl_getset(b, "Terminal/Keyboard", "appkeypad",
1374 "Application keypad settings:");
1375 ctrl_radiobuttons(s, "Initial state of cursor keys:", 'r', 3,
1376 HELPCTX(keyboard_appcursor),
1377 dlg_stdradiobutton_handler,
1378 I(offsetof(Config, app_cursor)),
1379 "Normal", I(0), "Application", I(1), NULL);
1380 ctrl_radiobuttons(s, "Initial state of numeric keypad:", 'n', 3,
1381 HELPCTX(keyboard_appkeypad),
1382 numeric_keypad_handler, P(NULL),
1383 "Normal", I(0), "Application", I(1), "NetHack", I(2),
1387 * The Terminal/Bell panel.
1389 ctrl_settitle(b, "Terminal/Bell",
1390 "Options controlling the terminal bell");
1392 s = ctrl_getset(b, "Terminal/Bell", "style", "Set the style of bell");
1393 ctrl_radiobuttons(s, "Action to happen when a bell occurs:", 'b', 1,
1394 HELPCTX(bell_style),
1395 dlg_stdradiobutton_handler, I(offsetof(Config, beep)),
1396 "None (bell disabled)", I(BELL_DISABLED),
1397 "Make default system alert sound", I(BELL_DEFAULT),
1398 "Visual bell (flash window)", I(BELL_VISUAL), NULL);
1400 s = ctrl_getset(b, "Terminal/Bell", "overload",
1401 "Control the bell overload behaviour");
1402 ctrl_checkbox(s, "Bell is temporarily disabled when over-used", 'd',
1403 HELPCTX(bell_overload),
1404 dlg_stdcheckbox_handler, I(offsetof(Config,bellovl)));
1405 ctrl_editbox(s, "Over-use means this many bells...", 'm', 20,
1406 HELPCTX(bell_overload),
1407 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_n)), I(-1));
1408 ctrl_editbox(s, "... in this many seconds", 't', 20,
1409 HELPCTX(bell_overload),
1410 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_t)),
1412 ctrl_text(s, "The bell is re-enabled after a few seconds of silence.",
1413 HELPCTX(bell_overload));
1414 ctrl_editbox(s, "Seconds of silence required", 's', 20,
1415 HELPCTX(bell_overload),
1416 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_s)),
1420 * The Terminal/Features panel.
1422 ctrl_settitle(b, "Terminal/Features",
1423 "Enabling and disabling advanced terminal features");
1425 s = ctrl_getset(b, "Terminal/Features", "main", NULL);
1426 ctrl_checkbox(s, "Disable application cursor keys mode", 'u',
1427 HELPCTX(features_application),
1428 dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_c)));
1429 ctrl_checkbox(s, "Disable application keypad mode", 'k',
1430 HELPCTX(features_application),
1431 dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_k)));
1432 ctrl_checkbox(s, "Disable xterm-style mouse reporting", 'x',
1433 HELPCTX(features_mouse),
1434 dlg_stdcheckbox_handler, I(offsetof(Config,no_mouse_rep)));
1435 ctrl_checkbox(s, "Disable remote-controlled terminal resizing", 's',
1436 HELPCTX(features_resize),
1437 dlg_stdcheckbox_handler,
1438 I(offsetof(Config,no_remote_resize)));
1439 ctrl_checkbox(s, "Disable switching to alternate terminal screen", 'w',
1440 HELPCTX(features_altscreen),
1441 dlg_stdcheckbox_handler, I(offsetof(Config,no_alt_screen)));
1442 ctrl_checkbox(s, "Disable remote-controlled window title changing", 't',
1443 HELPCTX(features_retitle),
1444 dlg_stdcheckbox_handler,
1445 I(offsetof(Config,no_remote_wintitle)));
1446 ctrl_radiobuttons(s, "Response to remote title query (SECURITY):", 'q', 3,
1447 HELPCTX(features_qtitle),
1448 dlg_stdradiobutton_handler,
1449 I(offsetof(Config,remote_qtitle_action)),
1450 "None", I(TITLE_NONE),
1451 "Empty string", I(TITLE_EMPTY),
1452 "Window title", I(TITLE_REAL), NULL);
1453 ctrl_checkbox(s, "Disable destructive backspace on server sending ^?",'b',
1454 HELPCTX(features_dbackspace),
1455 dlg_stdcheckbox_handler, I(offsetof(Config,no_dbackspace)));
1456 ctrl_checkbox(s, "Disable remote-controlled character set configuration",
1457 'r', HELPCTX(features_charset), dlg_stdcheckbox_handler,
1458 I(offsetof(Config,no_remote_charset)));
1459 ctrl_checkbox(s, "Disable Arabic text shaping",
1460 'l', HELPCTX(features_arabicshaping), dlg_stdcheckbox_handler,
1461 I(offsetof(Config, arabicshaping)));
1462 ctrl_checkbox(s, "Disable bidirectional text display",
1463 'd', HELPCTX(features_bidi), dlg_stdcheckbox_handler,
1464 I(offsetof(Config, bidi)));
1469 str = dupprintf("Options controlling %s's window", appname);
1470 ctrl_settitle(b, "Window", str);
1473 s = ctrl_getset(b, "Window", "size", "Set the size of the window");
1474 ctrl_columns(s, 2, 50, 50);
1475 c = ctrl_editbox(s, "Columns", 'm', 100,
1476 HELPCTX(window_size),
1477 dlg_stdeditbox_handler, I(offsetof(Config,width)), I(-1));
1478 c->generic.column = 0;
1479 c = ctrl_editbox(s, "Rows", 'r', 100,
1480 HELPCTX(window_size),
1481 dlg_stdeditbox_handler, I(offsetof(Config,height)),I(-1));
1482 c->generic.column = 1;
1483 ctrl_columns(s, 1, 100);
1485 s = ctrl_getset(b, "Window", "scrollback",
1486 "Control the scrollback in the window");
1487 ctrl_editbox(s, "Lines of scrollback", 's', 50,
1488 HELPCTX(window_scrollback),
1489 dlg_stdeditbox_handler, I(offsetof(Config,savelines)), I(-1));
1490 ctrl_checkbox(s, "Display scrollbar", 'd',
1491 HELPCTX(window_scrollback),
1492 dlg_stdcheckbox_handler, I(offsetof(Config,scrollbar)));
1493 ctrl_checkbox(s, "Reset scrollback on keypress", 'k',
1494 HELPCTX(window_scrollback),
1495 dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_key)));
1496 ctrl_checkbox(s, "Reset scrollback on display activity", 'p',
1497 HELPCTX(window_scrollback),
1498 dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_disp)));
1499 ctrl_checkbox(s, "Push erased text into scrollback", 'e',
1500 HELPCTX(window_erased),
1501 dlg_stdcheckbox_handler,
1502 I(offsetof(Config,erase_to_scrollback)));
1505 * The Window/Appearance panel.
1507 str = dupprintf("Configure the appearance of %s's window", appname);
1508 ctrl_settitle(b, "Window/Appearance", str);
1511 s = ctrl_getset(b, "Window/Appearance", "cursor",
1512 "Adjust the use of the cursor");
1513 ctrl_radiobuttons(s, "Cursor appearance:", NO_SHORTCUT, 3,
1514 HELPCTX(appearance_cursor),
1515 dlg_stdradiobutton_handler,
1516 I(offsetof(Config, cursor_type)),
1518 "Underline", 'u', I(1),
1519 "Vertical line", 'v', I(2), NULL);
1520 ctrl_checkbox(s, "Cursor blinks", 'b',
1521 HELPCTX(appearance_cursor),
1522 dlg_stdcheckbox_handler, I(offsetof(Config,blink_cur)));
1524 s = ctrl_getset(b, "Window/Appearance", "font",
1526 ctrl_fontsel(s, "Font used in the terminal window", 'n',
1527 HELPCTX(appearance_font),
1528 dlg_stdfontsel_handler, I(offsetof(Config, font)));
1530 s = ctrl_getset(b, "Window/Appearance", "mouse",
1531 "Adjust the use of the mouse pointer");
1532 ctrl_checkbox(s, "Hide mouse pointer when typing in window", 'p',
1533 HELPCTX(appearance_hidemouse),
1534 dlg_stdcheckbox_handler, I(offsetof(Config,hide_mouseptr)));
1536 s = ctrl_getset(b, "Window/Appearance", "border",
1537 "Adjust the window border");
1538 ctrl_editbox(s, "Gap between text and window edge:", 'e', 20,
1539 HELPCTX(appearance_border),
1540 dlg_stdeditbox_handler,
1541 I(offsetof(Config,window_border)), I(-1));
1544 * The Window/Behaviour panel.
1546 str = dupprintf("Configure the behaviour of %s's window", appname);
1547 ctrl_settitle(b, "Window/Behaviour", str);
1550 s = ctrl_getset(b, "Window/Behaviour", "title",
1551 "Adjust the behaviour of the window title");
1552 ctrl_editbox(s, "Window title:", 't', 100,
1553 HELPCTX(appearance_title),
1554 dlg_stdeditbox_handler, I(offsetof(Config,wintitle)),
1555 I(sizeof(((Config *)0)->wintitle)));
1556 ctrl_checkbox(s, "Separate window and icon titles", 'i',
1557 HELPCTX(appearance_title),
1558 dlg_stdcheckbox_handler,
1559 I(CHECKBOX_INVERT | offsetof(Config,win_name_always)));
1561 s = ctrl_getset(b, "Window/Behaviour", "main", NULL);
1562 ctrl_checkbox(s, "Warn before closing window", 'w',
1563 HELPCTX(behaviour_closewarn),
1564 dlg_stdcheckbox_handler, I(offsetof(Config,warn_on_close)));
1567 * The Window/Translation panel.
1569 ctrl_settitle(b, "Window/Translation",
1570 "Options controlling character set translation");
1572 s = ctrl_getset(b, "Window/Translation", "trans",
1573 "Character set translation on received data");
1574 ctrl_combobox(s, "Received data assumed to be in which character set:",
1575 'r', 100, HELPCTX(translation_codepage),
1576 codepage_handler, P(NULL), P(NULL));
1578 s = ctrl_getset(b, "Window/Translation", "tweaks", NULL);
1579 ctrl_checkbox(s, "Treat CJK ambiguous characters as wide", 'w',
1580 HELPCTX(translation_cjk_ambig_wide),
1581 dlg_stdcheckbox_handler, I(offsetof(Config,cjk_ambig_wide)));
1583 str = dupprintf("Adjust how %s handles line drawing characters", appname);
1584 s = ctrl_getset(b, "Window/Translation", "linedraw", str);
1586 ctrl_radiobuttons(s, "Handling of line drawing characters:", NO_SHORTCUT,1,
1587 HELPCTX(translation_linedraw),
1588 dlg_stdradiobutton_handler,
1589 I(offsetof(Config, vtmode)),
1590 "Use Unicode line drawing code points",'u',I(VT_UNICODE),
1591 "Poor man's line drawing (+, - and |)",'p',I(VT_POORMAN),
1593 ctrl_checkbox(s, "Copy and paste line drawing characters as lqqqk",'d',
1594 HELPCTX(selection_linedraw),
1595 dlg_stdcheckbox_handler, I(offsetof(Config,rawcnp)));
1598 * The Window/Selection panel.
1600 ctrl_settitle(b, "Window/Selection", "Options controlling copy and paste");
1602 s = ctrl_getset(b, "Window/Selection", "mouse",
1603 "Control use of mouse");
1604 ctrl_checkbox(s, "Shift overrides application's use of mouse", 'p',
1605 HELPCTX(selection_shiftdrag),
1606 dlg_stdcheckbox_handler, I(offsetof(Config,mouse_override)));
1607 ctrl_radiobuttons(s,
1608 "Default selection mode (Alt+drag does the other one):",
1610 HELPCTX(selection_rect),
1611 dlg_stdradiobutton_handler,
1612 I(offsetof(Config, rect_select)),
1613 "Normal", 'n', I(0),
1614 "Rectangular block", 'r', I(1), NULL);
1616 s = ctrl_getset(b, "Window/Selection", "charclass",
1617 "Control the select-one-word-at-a-time mode");
1618 ccd = (struct charclass_data *)
1619 ctrl_alloc(b, sizeof(struct charclass_data));
1620 ccd->listbox = ctrl_listbox(s, "Character classes:", 'e',
1621 HELPCTX(selection_charclasses),
1622 charclass_handler, P(ccd));
1623 ccd->listbox->listbox.multisel = 1;
1624 ccd->listbox->listbox.ncols = 4;
1625 ccd->listbox->listbox.percentages = snewn(4, int);
1626 ccd->listbox->listbox.percentages[0] = 15;
1627 ccd->listbox->listbox.percentages[1] = 25;
1628 ccd->listbox->listbox.percentages[2] = 20;
1629 ccd->listbox->listbox.percentages[3] = 40;
1630 ctrl_columns(s, 2, 67, 33);
1631 ccd->editbox = ctrl_editbox(s, "Set to class", 't', 50,
1632 HELPCTX(selection_charclasses),
1633 charclass_handler, P(ccd), P(NULL));
1634 ccd->editbox->generic.column = 0;
1635 ccd->button = ctrl_pushbutton(s, "Set", 's',
1636 HELPCTX(selection_charclasses),
1637 charclass_handler, P(ccd));
1638 ccd->button->generic.column = 1;
1639 ctrl_columns(s, 1, 100);
1642 * The Window/Colours panel.
1644 ctrl_settitle(b, "Window/Colours", "Options controlling use of colours");
1646 s = ctrl_getset(b, "Window/Colours", "general",
1647 "General options for colour usage");
1648 ctrl_checkbox(s, "Allow terminal to specify ANSI colours", 'i',
1649 HELPCTX(colours_ansi),
1650 dlg_stdcheckbox_handler, I(offsetof(Config,ansi_colour)));
1651 ctrl_checkbox(s, "Allow terminal to use xterm 256-colour mode", '2',
1652 HELPCTX(colours_xterm256), dlg_stdcheckbox_handler,
1653 I(offsetof(Config,xterm_256_colour)));
1654 ctrl_checkbox(s, "Bolded text is a different colour", 'b',
1655 HELPCTX(colours_bold),
1656 dlg_stdcheckbox_handler, I(offsetof(Config,bold_colour)));
1658 str = dupprintf("Adjust the precise colours %s displays", appname);
1659 s = ctrl_getset(b, "Window/Colours", "adjust", str);
1661 ctrl_text(s, "Select a colour from the list, and then click the"
1662 " Modify button to change its appearance.",
1663 HELPCTX(colours_config));
1664 ctrl_columns(s, 2, 67, 33);
1665 cd = (struct colour_data *)ctrl_alloc(b, sizeof(struct colour_data));
1666 cd->listbox = ctrl_listbox(s, "Select a colour to adjust:", 'u',
1667 HELPCTX(colours_config), colour_handler, P(cd));
1668 cd->listbox->generic.column = 0;
1669 cd->listbox->listbox.height = 7;
1670 c = ctrl_text(s, "RGB value:", HELPCTX(colours_config));
1671 c->generic.column = 1;
1672 cd->redit = ctrl_editbox(s, "Red", 'r', 50, HELPCTX(colours_config),
1673 colour_handler, P(cd), P(NULL));
1674 cd->redit->generic.column = 1;
1675 cd->gedit = ctrl_editbox(s, "Green", 'n', 50, HELPCTX(colours_config),
1676 colour_handler, P(cd), P(NULL));
1677 cd->gedit->generic.column = 1;
1678 cd->bedit = ctrl_editbox(s, "Blue", 'e', 50, HELPCTX(colours_config),
1679 colour_handler, P(cd), P(NULL));
1680 cd->bedit->generic.column = 1;
1681 cd->button = ctrl_pushbutton(s, "Modify", 'm', HELPCTX(colours_config),
1682 colour_handler, P(cd));
1683 cd->button->generic.column = 1;
1684 ctrl_columns(s, 1, 100);
1687 * The Connection panel. This doesn't show up if we're in a
1688 * non-network utility such as pterm. We tell this by being
1689 * passed a protocol < 0.
1691 if (protocol >= 0) {
1692 ctrl_settitle(b, "Connection", "Options controlling the connection");
1694 s = ctrl_getset(b, "Connection", "keepalive",
1695 "Sending of null packets to keep session active");
1696 ctrl_editbox(s, "Seconds between keepalives (0 to turn off)", 'k', 20,
1697 HELPCTX(connection_keepalive),
1698 dlg_stdeditbox_handler, I(offsetof(Config,ping_interval)),
1702 s = ctrl_getset(b, "Connection", "tcp",
1703 "Low-level TCP connection options");
1704 ctrl_checkbox(s, "Disable Nagle's algorithm (TCP_NODELAY option)",
1705 'n', HELPCTX(connection_nodelay),
1706 dlg_stdcheckbox_handler,
1707 I(offsetof(Config,tcp_nodelay)));
1708 ctrl_checkbox(s, "Enable TCP keepalives (SO_KEEPALIVE option)",
1709 'p', HELPCTX(connection_tcpkeepalive),
1710 dlg_stdcheckbox_handler,
1711 I(offsetof(Config,tcp_keepalives)));
1713 s = ctrl_getset(b, "Connection", "ipversion",
1714 "Internet protocol version");
1715 ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
1716 HELPCTX(connection_ipversion),
1717 dlg_stdradiobutton_handler,
1718 I(offsetof(Config, addressfamily)),
1719 "Auto", 'u', I(ADDRTYPE_UNSPEC),
1720 "IPv4", '4', I(ADDRTYPE_IPV4),
1721 "IPv6", '6', I(ADDRTYPE_IPV6),
1727 * A sub-panel Connection/Data, containing options that
1728 * decide on data to send to the server.
1731 ctrl_settitle(b, "Connection/Data", "Data to send to the server");
1733 s = ctrl_getset(b, "Connection/Data", "login",
1735 ctrl_editbox(s, "Auto-login username", 'u', 50,
1736 HELPCTX(connection_username),
1737 dlg_stdeditbox_handler, I(offsetof(Config,username)),
1738 I(sizeof(((Config *)0)->username)));
1740 s = ctrl_getset(b, "Connection/Data", "term",
1741 "Terminal details");
1742 ctrl_editbox(s, "Terminal-type string", 't', 50,
1743 HELPCTX(connection_termtype),
1744 dlg_stdeditbox_handler, I(offsetof(Config,termtype)),
1745 I(sizeof(((Config *)0)->termtype)));
1746 ctrl_editbox(s, "Terminal speeds", 's', 50,
1747 HELPCTX(connection_termspeed),
1748 dlg_stdeditbox_handler, I(offsetof(Config,termspeed)),
1749 I(sizeof(((Config *)0)->termspeed)));
1751 s = ctrl_getset(b, "Connection/Data", "env",
1752 "Environment variables");
1753 ctrl_columns(s, 2, 80, 20);
1754 ed = (struct environ_data *)
1755 ctrl_alloc(b, sizeof(struct environ_data));
1756 ed->varbox = ctrl_editbox(s, "Variable", 'v', 60,
1757 HELPCTX(telnet_environ),
1758 environ_handler, P(ed), P(NULL));
1759 ed->varbox->generic.column = 0;
1760 ed->valbox = ctrl_editbox(s, "Value", 'l', 60,
1761 HELPCTX(telnet_environ),
1762 environ_handler, P(ed), P(NULL));
1763 ed->valbox->generic.column = 0;
1764 ed->addbutton = ctrl_pushbutton(s, "Add", 'd',
1765 HELPCTX(telnet_environ),
1766 environ_handler, P(ed));
1767 ed->addbutton->generic.column = 1;
1768 ed->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1769 HELPCTX(telnet_environ),
1770 environ_handler, P(ed));
1771 ed->rembutton->generic.column = 1;
1772 ctrl_columns(s, 1, 100);
1773 ed->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1774 HELPCTX(telnet_environ),
1775 environ_handler, P(ed));
1776 ed->listbox->listbox.height = 3;
1777 ed->listbox->listbox.ncols = 2;
1778 ed->listbox->listbox.percentages = snewn(2, int);
1779 ed->listbox->listbox.percentages[0] = 30;
1780 ed->listbox->listbox.percentages[1] = 70;
1787 * The Connection/Proxy panel.
1789 ctrl_settitle(b, "Connection/Proxy",
1790 "Options controlling proxy usage");
1792 s = ctrl_getset(b, "Connection/Proxy", "basics", NULL);
1793 ctrl_radiobuttons(s, "Proxy type:", 't', 3,
1794 HELPCTX(proxy_type),
1795 dlg_stdradiobutton_handler,
1796 I(offsetof(Config, proxy_type)),
1797 "None", I(PROXY_NONE),
1798 "SOCKS 4", I(PROXY_SOCKS4),
1799 "SOCKS 5", I(PROXY_SOCKS5),
1800 "HTTP", I(PROXY_HTTP),
1801 "Telnet", I(PROXY_TELNET),
1803 ctrl_columns(s, 2, 80, 20);
1804 c = ctrl_editbox(s, "Proxy hostname", 'y', 100,
1805 HELPCTX(proxy_main),
1806 dlg_stdeditbox_handler,
1807 I(offsetof(Config,proxy_host)),
1808 I(sizeof(((Config *)0)->proxy_host)));
1809 c->generic.column = 0;
1810 c = ctrl_editbox(s, "Port", 'p', 100,
1811 HELPCTX(proxy_main),
1812 dlg_stdeditbox_handler,
1813 I(offsetof(Config,proxy_port)),
1815 c->generic.column = 1;
1816 ctrl_columns(s, 1, 100);
1817 ctrl_editbox(s, "Exclude Hosts/IPs", 'e', 100,
1818 HELPCTX(proxy_exclude),
1819 dlg_stdeditbox_handler,
1820 I(offsetof(Config,proxy_exclude_list)),
1821 I(sizeof(((Config *)0)->proxy_exclude_list)));
1822 ctrl_checkbox(s, "Consider proxying local host connections", 'x',
1823 HELPCTX(proxy_exclude),
1824 dlg_stdcheckbox_handler,
1825 I(offsetof(Config,even_proxy_localhost)));
1826 ctrl_radiobuttons(s, "Do DNS name lookup at proxy end:", 'd', 3,
1828 dlg_stdradiobutton_handler,
1829 I(offsetof(Config, proxy_dns)),
1832 "Yes", I(FORCE_ON), NULL);
1833 ctrl_editbox(s, "Username", 'u', 60,
1834 HELPCTX(proxy_auth),
1835 dlg_stdeditbox_handler,
1836 I(offsetof(Config,proxy_username)),
1837 I(sizeof(((Config *)0)->proxy_username)));
1838 c = ctrl_editbox(s, "Password", 'w', 60,
1839 HELPCTX(proxy_auth),
1840 dlg_stdeditbox_handler,
1841 I(offsetof(Config,proxy_password)),
1842 I(sizeof(((Config *)0)->proxy_password)));
1843 c->editbox.password = 1;
1844 ctrl_editbox(s, "Telnet command", 'm', 100,
1845 HELPCTX(proxy_command),
1846 dlg_stdeditbox_handler,
1847 I(offsetof(Config,proxy_telnet_command)),
1848 I(sizeof(((Config *)0)->proxy_telnet_command)));
1852 * The Telnet panel exists in the base config box, and in a
1853 * mid-session reconfig box _if_ we're using Telnet.
1855 if (!midsession || protocol == PROT_TELNET) {
1857 * The Connection/Telnet panel.
1859 ctrl_settitle(b, "Connection/Telnet",
1860 "Options controlling Telnet connections");
1862 s = ctrl_getset(b, "Connection/Telnet", "protocol",
1863 "Telnet protocol adjustments");
1866 ctrl_radiobuttons(s, "Handling of OLD_ENVIRON ambiguity:",
1868 HELPCTX(telnet_oldenviron),
1869 dlg_stdradiobutton_handler,
1870 I(offsetof(Config, rfc_environ)),
1871 "BSD (commonplace)", 'b', I(0),
1872 "RFC 1408 (unusual)", 'f', I(1), NULL);
1873 ctrl_radiobuttons(s, "Telnet negotiation mode:", 't', 2,
1874 HELPCTX(telnet_passive),
1875 dlg_stdradiobutton_handler,
1876 I(offsetof(Config, passive_telnet)),
1877 "Passive", I(1), "Active", I(0), NULL);
1879 ctrl_checkbox(s, "Keyboard sends Telnet special commands", 'k',
1880 HELPCTX(telnet_specialkeys),
1881 dlg_stdcheckbox_handler,
1882 I(offsetof(Config,telnet_keyboard)));
1883 ctrl_checkbox(s, "Return key sends Telnet New Line instead of ^M",
1884 'm', HELPCTX(telnet_newline),
1885 dlg_stdcheckbox_handler,
1886 I(offsetof(Config,telnet_newline)));
1892 * The Connection/Rlogin panel.
1894 ctrl_settitle(b, "Connection/Rlogin",
1895 "Options controlling Rlogin connections");
1897 s = ctrl_getset(b, "Connection/Rlogin", "data",
1898 "Data to send to the server");
1899 ctrl_editbox(s, "Local username:", 'l', 50,
1900 HELPCTX(rlogin_localuser),
1901 dlg_stdeditbox_handler, I(offsetof(Config,localusername)),
1902 I(sizeof(((Config *)0)->localusername)));
1907 * All the SSH stuff is omitted in PuTTYtel, or in a reconfig
1908 * when we're not doing SSH.
1911 if (backend_from_proto(PROT_SSH) && (!midsession || protocol == PROT_SSH)) {
1914 * The Connection/SSH panel.
1916 ctrl_settitle(b, "Connection/SSH",
1917 "Options controlling SSH connections");
1919 if (midsession && protcfginfo == 1) {
1920 s = ctrl_getset(b, "Connection/SSH", "disclaimer", NULL);
1921 ctrl_text(s, "Nothing on this panel may be reconfigured in mid-"
1922 "session; it is only here so that sub-panels of it can "
1923 "exist without looking strange.", HELPCTX(no_help));
1928 s = ctrl_getset(b, "Connection/SSH", "data",
1929 "Data to send to the server");
1930 ctrl_editbox(s, "Remote command:", 'r', 100,
1931 HELPCTX(ssh_command),
1932 dlg_stdeditbox_handler, I(offsetof(Config,remote_cmd)),
1933 I(sizeof(((Config *)0)->remote_cmd)));
1935 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1936 ctrl_checkbox(s, "Don't start a shell or command at all", 'n',
1937 HELPCTX(ssh_noshell),
1938 dlg_stdcheckbox_handler,
1939 I(offsetof(Config,ssh_no_shell)));
1942 if (!midsession || protcfginfo != 1) {
1943 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1945 ctrl_checkbox(s, "Enable compression", 'e',
1946 HELPCTX(ssh_compress),
1947 dlg_stdcheckbox_handler,
1948 I(offsetof(Config,compression)));
1952 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1954 ctrl_radiobuttons(s, "Preferred SSH protocol version:", NO_SHORTCUT, 4,
1955 HELPCTX(ssh_protocol),
1956 dlg_stdradiobutton_handler,
1957 I(offsetof(Config, sshprot)),
1958 "1 only", 'l', I(0),
1961 "2 only", 'y', I(3), NULL);
1964 if (!midsession || protcfginfo != 1) {
1965 s = ctrl_getset(b, "Connection/SSH", "encryption", "Encryption options");
1966 c = ctrl_draglist(s, "Encryption cipher selection policy:", 's',
1967 HELPCTX(ssh_ciphers),
1968 cipherlist_handler, P(NULL));
1969 c->listbox.height = 6;
1971 ctrl_checkbox(s, "Enable legacy use of single-DES in SSH-2", 'i',
1972 HELPCTX(ssh_ciphers),
1973 dlg_stdcheckbox_handler,
1974 I(offsetof(Config,ssh2_des_cbc)));
1978 * The Connection/SSH/Kex panel. (Owing to repeat key
1979 * exchange, this is all meaningful in mid-session _if_
1980 * we're using SSH-2 or haven't decided yet.)
1982 if (protcfginfo != 1) {
1983 ctrl_settitle(b, "Connection/SSH/Kex",
1984 "Options controlling SSH key exchange");
1986 s = ctrl_getset(b, "Connection/SSH/Kex", "main",
1987 "Key exchange algorithm options");
1988 c = ctrl_draglist(s, "Algorithm selection policy:", 's',
1989 HELPCTX(ssh_kexlist),
1990 kexlist_handler, P(NULL));
1991 c->listbox.height = 5;
1993 s = ctrl_getset(b, "Connection/SSH/Kex", "repeat",
1994 "Options controlling key re-exchange");
1996 ctrl_editbox(s, "Max minutes before rekey (0 for no limit)", 't', 20,
1997 HELPCTX(ssh_kex_repeat),
1998 dlg_stdeditbox_handler,
1999 I(offsetof(Config,ssh_rekey_time)),
2001 ctrl_editbox(s, "Max data before rekey (0 for no limit)", 'x', 20,
2002 HELPCTX(ssh_kex_repeat),
2003 dlg_stdeditbox_handler,
2004 I(offsetof(Config,ssh_rekey_data)),
2006 ctrl_text(s, "(Use 1M for 1 megabyte, 1G for 1 gigabyte etc)",
2007 HELPCTX(ssh_kex_repeat));
2013 * The Connection/SSH/Auth panel.
2015 ctrl_settitle(b, "Connection/SSH/Auth",
2016 "Options controlling SSH authentication");
2018 s = ctrl_getset(b, "Connection/SSH/Auth", "main", NULL);
2019 ctrl_checkbox(s, "Bypass authentication entirely (SSH-2 only)", 'b',
2020 HELPCTX(ssh_auth_bypass),
2021 dlg_stdcheckbox_handler,
2022 I(offsetof(Config,ssh_no_userauth)));
2024 s = ctrl_getset(b, "Connection/SSH/Auth", "methods",
2025 "Authentication methods");
2026 ctrl_checkbox(s, "Attempt authentication using Pageant", 'p',
2027 HELPCTX(ssh_auth_pageant),
2028 dlg_stdcheckbox_handler,
2029 I(offsetof(Config,tryagent)));
2030 ctrl_checkbox(s, "Attempt TIS or CryptoCard auth (SSH-1)", 'm',
2031 HELPCTX(ssh_auth_tis),
2032 dlg_stdcheckbox_handler,
2033 I(offsetof(Config,try_tis_auth)));
2034 ctrl_checkbox(s, "Attempt \"keyboard-interactive\" auth (SSH-2)",
2035 'i', HELPCTX(ssh_auth_ki),
2036 dlg_stdcheckbox_handler,
2037 I(offsetof(Config,try_ki_auth)));
2039 s = ctrl_getset(b, "Connection/SSH/Auth", "params",
2040 "Authentication parameters");
2041 ctrl_checkbox(s, "Allow agent forwarding", 'f',
2042 HELPCTX(ssh_auth_agentfwd),
2043 dlg_stdcheckbox_handler, I(offsetof(Config,agentfwd)));
2044 ctrl_checkbox(s, "Allow attempted changes of username in SSH-2", 'u',
2045 HELPCTX(ssh_auth_changeuser),
2046 dlg_stdcheckbox_handler,
2047 I(offsetof(Config,change_username)));
2048 ctrl_filesel(s, "Private key file for authentication:", 'k',
2049 FILTER_KEY_FILES, FALSE, "Select private key file",
2050 HELPCTX(ssh_auth_privkey),
2051 dlg_stdfilesel_handler, I(offsetof(Config, keyfile)));
2056 * The Connection/SSH/TTY panel.
2058 ctrl_settitle(b, "Connection/SSH/TTY", "Remote terminal settings");
2060 s = ctrl_getset(b, "Connection/SSH/TTY", "sshtty", NULL);
2061 ctrl_checkbox(s, "Don't allocate a pseudo-terminal", 'p',
2063 dlg_stdcheckbox_handler,
2064 I(offsetof(Config,nopty)));
2066 s = ctrl_getset(b, "Connection/SSH/TTY", "ttymodes",
2068 td = (struct ttymodes_data *)
2069 ctrl_alloc(b, sizeof(struct ttymodes_data));
2070 ctrl_columns(s, 2, 75, 25);
2071 c = ctrl_text(s, "Terminal modes to send:", HELPCTX(ssh_ttymodes));
2072 c->generic.column = 0;
2073 td->rembutton = ctrl_pushbutton(s, "Remove", 'r',
2074 HELPCTX(ssh_ttymodes),
2075 ttymodes_handler, P(td));
2076 td->rembutton->generic.column = 1;
2077 td->rembutton->generic.tabdelay = 1;
2078 ctrl_columns(s, 1, 100);
2079 td->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
2080 HELPCTX(ssh_ttymodes),
2081 ttymodes_handler, P(td));
2082 td->listbox->listbox.multisel = 1;
2083 td->listbox->listbox.height = 4;
2084 td->listbox->listbox.ncols = 2;
2085 td->listbox->listbox.percentages = snewn(2, int);
2086 td->listbox->listbox.percentages[0] = 40;
2087 td->listbox->listbox.percentages[1] = 60;
2088 ctrl_tabdelay(s, td->rembutton);
2089 ctrl_columns(s, 2, 75, 25);
2090 td->modelist = ctrl_droplist(s, "Mode:", 'm', 67,
2091 HELPCTX(ssh_ttymodes),
2092 ttymodes_handler, P(td));
2093 td->modelist->generic.column = 0;
2094 td->addbutton = ctrl_pushbutton(s, "Add", 'd',
2095 HELPCTX(ssh_ttymodes),
2096 ttymodes_handler, P(td));
2097 td->addbutton->generic.column = 1;
2098 td->addbutton->generic.tabdelay = 1;
2099 ctrl_columns(s, 1, 100); /* column break */
2100 /* Bit of a hack to get the value radio buttons and
2101 * edit-box on the same row. */
2102 ctrl_columns(s, 3, 25, 50, 25);
2103 c = ctrl_text(s, "Value:", HELPCTX(ssh_ttymodes));
2104 c->generic.column = 0;
2105 td->valradio = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 2,
2106 HELPCTX(ssh_ttymodes),
2107 ttymodes_handler, P(td),
2108 "Auto", NO_SHORTCUT, P(NULL),
2109 "This:", NO_SHORTCUT, P(NULL),
2111 td->valradio->generic.column = 1;
2112 td->valbox = ctrl_editbox(s, NULL, NO_SHORTCUT, 100,
2113 HELPCTX(ssh_ttymodes),
2114 ttymodes_handler, P(td), P(NULL));
2115 td->valbox->generic.column = 2;
2116 ctrl_tabdelay(s, td->addbutton);
2122 * The Connection/SSH/X11 panel.
2124 ctrl_settitle(b, "Connection/SSH/X11",
2125 "Options controlling SSH X11 forwarding");
2127 s = ctrl_getset(b, "Connection/SSH/X11", "x11", "X11 forwarding");
2128 ctrl_checkbox(s, "Enable X11 forwarding", 'e',
2129 HELPCTX(ssh_tunnels_x11),
2130 dlg_stdcheckbox_handler,I(offsetof(Config,x11_forward)));
2131 ctrl_editbox(s, "X display location", 'x', 50,
2132 HELPCTX(ssh_tunnels_x11),
2133 dlg_stdeditbox_handler, I(offsetof(Config,x11_display)),
2134 I(sizeof(((Config *)0)->x11_display)));
2135 ctrl_radiobuttons(s, "Remote X11 authentication protocol", 'u', 2,
2136 HELPCTX(ssh_tunnels_x11auth),
2137 dlg_stdradiobutton_handler,
2138 I(offsetof(Config, x11_auth)),
2139 "MIT-Magic-Cookie-1", I(X11_MIT),
2140 "XDM-Authorization-1", I(X11_XDM), NULL);
2144 * The Tunnels panel _is_ still available in mid-session.
2146 ctrl_settitle(b, "Connection/SSH/Tunnels",
2147 "Options controlling SSH port forwarding");
2149 s = ctrl_getset(b, "Connection/SSH/Tunnels", "portfwd",
2151 ctrl_checkbox(s, "Local ports accept connections from other hosts",'t',
2152 HELPCTX(ssh_tunnels_portfwd_localhost),
2153 dlg_stdcheckbox_handler,
2154 I(offsetof(Config,lport_acceptall)));
2155 ctrl_checkbox(s, "Remote ports do the same (SSH-2 only)", 'p',
2156 HELPCTX(ssh_tunnels_portfwd_localhost),
2157 dlg_stdcheckbox_handler,
2158 I(offsetof(Config,rport_acceptall)));
2160 ctrl_columns(s, 3, 55, 20, 25);
2161 c = ctrl_text(s, "Forwarded ports:", HELPCTX(ssh_tunnels_portfwd));
2162 c->generic.column = COLUMN_FIELD(0,2);
2163 /* You want to select from the list, _then_ hit Remove. So tab order
2164 * should be that way round. */
2165 pfd = (struct portfwd_data *)ctrl_alloc(b,sizeof(struct portfwd_data));
2166 pfd->rembutton = ctrl_pushbutton(s, "Remove", 'r',
2167 HELPCTX(ssh_tunnels_portfwd),
2168 portfwd_handler, P(pfd));
2169 pfd->rembutton->generic.column = 2;
2170 pfd->rembutton->generic.tabdelay = 1;
2171 pfd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
2172 HELPCTX(ssh_tunnels_portfwd),
2173 portfwd_handler, P(pfd));
2174 pfd->listbox->listbox.height = 3;
2175 pfd->listbox->listbox.ncols = 2;
2176 pfd->listbox->listbox.percentages = snewn(2, int);
2177 pfd->listbox->listbox.percentages[0] = 20;
2178 pfd->listbox->listbox.percentages[1] = 80;
2179 ctrl_tabdelay(s, pfd->rembutton);
2180 ctrl_text(s, "Add new forwarded port:", HELPCTX(ssh_tunnels_portfwd));
2181 /* You want to enter source, destination and type, _then_ hit Add.
2182 * Again, we adjust the tab order to reflect this. */
2183 pfd->addbutton = ctrl_pushbutton(s, "Add", 'd',
2184 HELPCTX(ssh_tunnels_portfwd),
2185 portfwd_handler, P(pfd));
2186 pfd->addbutton->generic.column = 2;
2187 pfd->addbutton->generic.tabdelay = 1;
2188 pfd->sourcebox = ctrl_editbox(s, "Source port", 's', 40,
2189 HELPCTX(ssh_tunnels_portfwd),
2190 portfwd_handler, P(pfd), P(NULL));
2191 pfd->sourcebox->generic.column = 0;
2192 pfd->destbox = ctrl_editbox(s, "Destination", 'i', 67,
2193 HELPCTX(ssh_tunnels_portfwd),
2194 portfwd_handler, P(pfd), P(NULL));
2195 pfd->direction = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
2196 HELPCTX(ssh_tunnels_portfwd),
2197 portfwd_handler, P(pfd),
2198 "Local", 'l', P(NULL),
2199 "Remote", 'm', P(NULL),
2200 "Dynamic", 'y', P(NULL),
2203 pfd->addressfamily =
2204 ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
2205 HELPCTX(ssh_tunnels_portfwd_ipversion),
2206 portfwd_handler, P(pfd),
2207 "Auto", 'u', I(ADDRTYPE_UNSPEC),
2208 "IPv4", '4', I(ADDRTYPE_IPV4),
2209 "IPv6", '6', I(ADDRTYPE_IPV6),
2212 ctrl_tabdelay(s, pfd->addbutton);
2213 ctrl_columns(s, 1, 100);
2217 * The Connection/SSH/Bugs panel.
2219 ctrl_settitle(b, "Connection/SSH/Bugs",
2220 "Workarounds for SSH server bugs");
2222 s = ctrl_getset(b, "Connection/SSH/Bugs", "main",
2223 "Detection of known bugs in SSH servers");
2224 ctrl_droplist(s, "Chokes on SSH-1 ignore messages", 'i', 20,
2225 HELPCTX(ssh_bugs_ignore1),
2226 sshbug_handler, I(offsetof(Config,sshbug_ignore1)));
2227 ctrl_droplist(s, "Refuses all SSH-1 password camouflage", 's', 20,
2228 HELPCTX(ssh_bugs_plainpw1),
2229 sshbug_handler, I(offsetof(Config,sshbug_plainpw1)));
2230 ctrl_droplist(s, "Chokes on SSH-1 RSA authentication", 'r', 20,
2231 HELPCTX(ssh_bugs_rsa1),
2232 sshbug_handler, I(offsetof(Config,sshbug_rsa1)));
2233 ctrl_droplist(s, "Miscomputes SSH-2 HMAC keys", 'm', 20,
2234 HELPCTX(ssh_bugs_hmac2),
2235 sshbug_handler, I(offsetof(Config,sshbug_hmac2)));
2236 ctrl_droplist(s, "Miscomputes SSH-2 encryption keys", 'e', 20,
2237 HELPCTX(ssh_bugs_derivekey2),
2238 sshbug_handler, I(offsetof(Config,sshbug_derivekey2)));
2239 ctrl_droplist(s, "Requires padding on SSH-2 RSA signatures", 'p', 20,
2240 HELPCTX(ssh_bugs_rsapad2),
2241 sshbug_handler, I(offsetof(Config,sshbug_rsapad2)));
2242 ctrl_droplist(s, "Misuses the session ID in SSH-2 PK auth", 'n', 20,
2243 HELPCTX(ssh_bugs_pksessid2),
2244 sshbug_handler, I(offsetof(Config,sshbug_pksessid2)));
2245 ctrl_droplist(s, "Handles SSH-2 key re-exchange badly", 'k', 20,
2246 HELPCTX(ssh_bugs_rekey2),
2247 sshbug_handler, I(offsetof(Config,sshbug_rekey2)));