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 numeric_keypad_handler(union control *ctrl, void *dlg,
54 void *data, int event)
57 Config *cfg = (Config *)data;
59 * This function works much like the standard radio button
60 * handler, but it has to handle two fields in Config.
62 if (event == EVENT_REFRESH) {
63 if (cfg->nethack_keypad)
65 else if (cfg->app_keypad)
69 assert(button < ctrl->radio.nbuttons);
70 dlg_radiobutton_set(ctrl, dlg, button);
71 } else if (event == EVENT_VALCHANGE) {
72 button = dlg_radiobutton_get(ctrl, dlg);
73 assert(button >= 0 && button < ctrl->radio.nbuttons);
75 cfg->app_keypad = FALSE;
76 cfg->nethack_keypad = TRUE;
78 cfg->app_keypad = (button != 0);
79 cfg->nethack_keypad = FALSE;
84 static void cipherlist_handler(union control *ctrl, void *dlg,
85 void *data, int event)
87 Config *cfg = (Config *)data;
88 if (event == EVENT_REFRESH) {
91 static const struct { char *s; int c; } ciphers[] = {
92 { "3DES", CIPHER_3DES },
93 { "Blowfish", CIPHER_BLOWFISH },
94 { "DES", CIPHER_DES },
95 { "AES (SSH 2 only)", CIPHER_AES },
96 { "-- warn below here --", CIPHER_WARN }
99 /* Set up the "selected ciphers" box. */
100 /* (cipherlist assumed to contain all ciphers) */
101 dlg_update_start(ctrl, dlg);
102 dlg_listbox_clear(ctrl, dlg);
103 for (i = 0; i < CIPHER_MAX; i++) {
104 int c = cfg->ssh_cipherlist[i];
107 for (j = 0; j < (sizeof ciphers) / (sizeof ciphers[0]); j++) {
108 if (ciphers[j].c == c) {
113 dlg_listbox_addwithid(ctrl, dlg, cstr, c);
115 dlg_update_done(ctrl, dlg);
117 } else if (event == EVENT_VALCHANGE) {
120 /* Update array to match the list box. */
121 for (i=0; i < CIPHER_MAX; i++)
122 cfg->ssh_cipherlist[i] = dlg_listbox_getid(ctrl, dlg, i);
127 static void kexlist_handler(union control *ctrl, void *dlg,
128 void *data, int event)
130 Config *cfg = (Config *)data;
131 if (event == EVENT_REFRESH) {
134 static const struct { char *s; int k; } kexes[] = {
135 { "Diffie-Hellman group 1", KEX_DHGROUP1 },
136 { "Diffie-Hellman group 14", KEX_DHGROUP14 },
137 { "Diffie-Hellman group exchange", KEX_DHGEX },
138 { "-- warn below here --", KEX_WARN }
141 /* Set up the "kex preference" box. */
142 /* (kexlist assumed to contain all algorithms) */
143 dlg_update_start(ctrl, dlg);
144 dlg_listbox_clear(ctrl, dlg);
145 for (i = 0; i < KEX_MAX; i++) {
146 int k = cfg->ssh_kexlist[i];
149 for (j = 0; j < (sizeof kexes) / (sizeof kexes[0]); j++) {
150 if (kexes[j].k == k) {
155 dlg_listbox_addwithid(ctrl, dlg, kstr, k);
157 dlg_update_done(ctrl, dlg);
159 } else if (event == EVENT_VALCHANGE) {
162 /* Update array to match the list box. */
163 for (i=0; i < KEX_MAX; i++)
164 cfg->ssh_kexlist[i] = dlg_listbox_getid(ctrl, dlg, i);
169 static void printerbox_handler(union control *ctrl, void *dlg,
170 void *data, int event)
172 Config *cfg = (Config *)data;
173 if (event == EVENT_REFRESH) {
177 dlg_update_start(ctrl, dlg);
179 * Some backends may wish to disable the drop-down list on
180 * this edit box. Be prepared for this.
182 if (ctrl->editbox.has_list) {
183 dlg_listbox_clear(ctrl, dlg);
184 dlg_listbox_add(ctrl, dlg, PRINTER_DISABLED_STRING);
185 pe = printer_start_enum(&nprinters);
186 for (i = 0; i < nprinters; i++)
187 dlg_listbox_add(ctrl, dlg, printer_get_name(pe, i));
188 printer_finish_enum(pe);
190 dlg_editbox_set(ctrl, dlg,
191 (*cfg->printer ? cfg->printer :
192 PRINTER_DISABLED_STRING));
193 dlg_update_done(ctrl, dlg);
194 } else if (event == EVENT_VALCHANGE) {
195 dlg_editbox_get(ctrl, dlg, cfg->printer, sizeof(cfg->printer));
196 if (!strcmp(cfg->printer, PRINTER_DISABLED_STRING))
197 *cfg->printer = '\0';
201 static void codepage_handler(union control *ctrl, void *dlg,
202 void *data, int event)
204 Config *cfg = (Config *)data;
205 if (event == EVENT_REFRESH) {
208 dlg_update_start(ctrl, dlg);
209 strcpy(cfg->line_codepage,
210 cp_name(decode_codepage(cfg->line_codepage)));
211 dlg_listbox_clear(ctrl, dlg);
212 for (i = 0; (cp = cp_enumerate(i)) != NULL; i++)
213 dlg_listbox_add(ctrl, dlg, cp);
214 dlg_editbox_set(ctrl, dlg, cfg->line_codepage);
215 dlg_update_done(ctrl, dlg);
216 } else if (event == EVENT_VALCHANGE) {
217 dlg_editbox_get(ctrl, dlg, cfg->line_codepage,
218 sizeof(cfg->line_codepage));
219 strcpy(cfg->line_codepage,
220 cp_name(decode_codepage(cfg->line_codepage)));
224 static void sshbug_handler(union control *ctrl, void *dlg,
225 void *data, int event)
227 if (event == EVENT_REFRESH) {
228 dlg_update_start(ctrl, dlg);
229 dlg_listbox_clear(ctrl, dlg);
230 dlg_listbox_addwithid(ctrl, dlg, "Auto", AUTO);
231 dlg_listbox_addwithid(ctrl, dlg, "Off", FORCE_OFF);
232 dlg_listbox_addwithid(ctrl, dlg, "On", FORCE_ON);
233 switch (*(int *)ATOFFSET(data, ctrl->listbox.context.i)) {
234 case AUTO: dlg_listbox_select(ctrl, dlg, 0); break;
235 case FORCE_OFF: dlg_listbox_select(ctrl, dlg, 1); break;
236 case FORCE_ON: dlg_listbox_select(ctrl, dlg, 2); break;
238 dlg_update_done(ctrl, dlg);
239 } else if (event == EVENT_SELCHANGE) {
240 int i = dlg_listbox_index(ctrl, dlg);
244 i = dlg_listbox_getid(ctrl, dlg, i);
245 *(int *)ATOFFSET(data, ctrl->listbox.context.i) = i;
249 #define SAVEDSESSION_LEN 2048
251 struct sessionsaver_data {
252 union control *editbox, *listbox, *loadbutton, *savebutton, *delbutton;
253 union control *okbutton, *cancelbutton;
254 struct sesslist *sesslist;
259 * Helper function to load the session selected in the list box, if
260 * any, as this is done in more than one place below. Returns 0 for
263 static int load_selected_session(struct sessionsaver_data *ssd,
265 void *dlg, Config *cfg)
267 int i = dlg_listbox_index(ssd->listbox, dlg);
273 isdef = !strcmp(ssd->sesslist->sessions[i], "Default Settings");
274 load_settings(ssd->sesslist->sessions[i], !isdef, cfg);
276 strncpy(savedsession, ssd->sesslist->sessions[i],
278 savedsession[SAVEDSESSION_LEN-1] = '\0';
280 savedsession[0] = '\0';
282 dlg_refresh(NULL, dlg);
283 /* Restore the selection, which might have been clobbered by
284 * changing the value of the edit box. */
285 dlg_listbox_select(ssd->listbox, dlg, i);
289 static void sessionsaver_handler(union control *ctrl, void *dlg,
290 void *data, int event)
292 Config *cfg = (Config *)data;
293 struct sessionsaver_data *ssd =
294 (struct sessionsaver_data *)ctrl->generic.context.p;
298 * The first time we're called in a new dialog, we must
299 * allocate space to store the current contents of the saved
300 * session edit box (since it must persist even when we switch
301 * panels, but is not part of the Config).
305 } else if (!dlg_get_privdata(ssd->editbox, dlg)) {
306 savedsession = (char *)
307 dlg_alloc_privdata(ssd->editbox, dlg, SAVEDSESSION_LEN);
308 savedsession[0] = '\0';
310 savedsession = dlg_get_privdata(ssd->editbox, dlg);
313 if (event == EVENT_REFRESH) {
314 if (ctrl == ssd->editbox) {
315 dlg_editbox_set(ctrl, dlg, savedsession);
316 } else if (ctrl == ssd->listbox) {
318 dlg_update_start(ctrl, dlg);
319 dlg_listbox_clear(ctrl, dlg);
320 for (i = 0; i < ssd->sesslist->nsessions; i++)
321 dlg_listbox_add(ctrl, dlg, ssd->sesslist->sessions[i]);
322 dlg_update_done(ctrl, dlg);
324 } else if (event == EVENT_VALCHANGE) {
325 if (ctrl == ssd->editbox) {
326 dlg_editbox_get(ctrl, dlg, savedsession,
329 } else if (event == EVENT_ACTION) {
330 if (!ssd->midsession &&
331 (ctrl == ssd->listbox ||
332 (ssd->loadbutton && ctrl == ssd->loadbutton))) {
334 * The user has double-clicked a session, or hit Load.
335 * We must load the selected session, and then
336 * terminate the configuration dialog _if_ there was a
337 * double-click on the list box _and_ that session
338 * contains a hostname.
340 if (load_selected_session(ssd, savedsession, dlg, cfg) &&
341 (ctrl == ssd->listbox && cfg->host[0])) {
342 dlg_end(dlg, 1); /* it's all over, and succeeded */
344 } else if (ctrl == ssd->savebutton) {
345 int isdef = !strcmp(savedsession, "Default Settings");
346 if (!savedsession[0]) {
347 int i = dlg_listbox_index(ssd->listbox, dlg);
352 isdef = !strcmp(ssd->sesslist->sessions[i], "Default Settings");
354 strncpy(savedsession, ssd->sesslist->sessions[i],
356 savedsession[SAVEDSESSION_LEN-1] = '\0';
358 savedsession[0] = '\0';
362 char *errmsg = save_settings(savedsession, !isdef, cfg);
364 dlg_error_msg(dlg, errmsg);
368 get_sesslist(ssd->sesslist, FALSE);
369 get_sesslist(ssd->sesslist, TRUE);
370 dlg_refresh(ssd->editbox, dlg);
371 dlg_refresh(ssd->listbox, dlg);
372 } else if (!ssd->midsession &&
373 ssd->delbutton && ctrl == ssd->delbutton) {
374 int i = dlg_listbox_index(ssd->listbox, dlg);
378 del_settings(ssd->sesslist->sessions[i]);
379 get_sesslist(ssd->sesslist, FALSE);
380 get_sesslist(ssd->sesslist, TRUE);
381 dlg_refresh(ssd->listbox, dlg);
383 } else if (ctrl == ssd->okbutton) {
384 if (ssd->midsession) {
385 /* In a mid-session Change Settings, Apply is always OK. */
390 * Annoying special case. If the `Open' button is
391 * pressed while no host name is currently set, _and_
392 * the session list previously had the focus, _and_
393 * there was a session selected in that which had a
394 * valid host name in it, then load it and go.
396 if (dlg_last_focused(ctrl, dlg) == ssd->listbox && !*cfg->host) {
398 if (!load_selected_session(ssd, savedsession, dlg, &cfg2)) {
402 /* If at this point we have a valid session, go! */
404 *cfg = cfg2; /* structure copy */
405 cfg->remote_cmd_ptr = cfg->remote_cmd; /* nasty */
413 * Otherwise, do the normal thing: if we have a valid
414 * session, get going.
420 } else if (ctrl == ssd->cancelbutton) {
426 struct charclass_data {
427 union control *listbox, *editbox, *button;
430 static void charclass_handler(union control *ctrl, void *dlg,
431 void *data, int event)
433 Config *cfg = (Config *)data;
434 struct charclass_data *ccd =
435 (struct charclass_data *)ctrl->generic.context.p;
437 if (event == EVENT_REFRESH) {
438 if (ctrl == ccd->listbox) {
440 dlg_update_start(ctrl, dlg);
441 dlg_listbox_clear(ctrl, dlg);
442 for (i = 0; i < 128; i++) {
444 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
445 (i >= 0x21 && i != 0x7F) ? i : ' ', cfg->wordness[i]);
446 dlg_listbox_add(ctrl, dlg, str);
448 dlg_update_done(ctrl, dlg);
450 } else if (event == EVENT_ACTION) {
451 if (ctrl == ccd->button) {
454 dlg_editbox_get(ccd->editbox, dlg, str, sizeof(str));
456 for (i = 0; i < 128; i++) {
457 if (dlg_listbox_issel(ccd->listbox, dlg, i))
458 cfg->wordness[i] = n;
460 dlg_refresh(ccd->listbox, dlg);
466 union control *listbox, *redit, *gedit, *bedit, *button;
469 static const char *const colours[] = {
470 "Default Foreground", "Default Bold Foreground",
471 "Default Background", "Default Bold Background",
472 "Cursor Text", "Cursor Colour",
473 "ANSI Black", "ANSI Black Bold",
474 "ANSI Red", "ANSI Red Bold",
475 "ANSI Green", "ANSI Green Bold",
476 "ANSI Yellow", "ANSI Yellow Bold",
477 "ANSI Blue", "ANSI Blue Bold",
478 "ANSI Magenta", "ANSI Magenta Bold",
479 "ANSI Cyan", "ANSI Cyan Bold",
480 "ANSI White", "ANSI White Bold"
483 static void colour_handler(union control *ctrl, void *dlg,
484 void *data, int event)
486 Config *cfg = (Config *)data;
487 struct colour_data *cd =
488 (struct colour_data *)ctrl->generic.context.p;
489 int update = FALSE, r, g, b;
491 if (event == EVENT_REFRESH) {
492 if (ctrl == cd->listbox) {
494 dlg_update_start(ctrl, dlg);
495 dlg_listbox_clear(ctrl, dlg);
496 for (i = 0; i < lenof(colours); i++)
497 dlg_listbox_add(ctrl, dlg, colours[i]);
498 dlg_update_done(ctrl, dlg);
499 dlg_editbox_set(cd->redit, dlg, "");
500 dlg_editbox_set(cd->gedit, dlg, "");
501 dlg_editbox_set(cd->bedit, dlg, "");
503 } else if (event == EVENT_SELCHANGE) {
504 if (ctrl == cd->listbox) {
505 /* The user has selected a colour. Update the RGB text. */
506 int i = dlg_listbox_index(ctrl, dlg);
511 r = cfg->colours[i][0];
512 g = cfg->colours[i][1];
513 b = cfg->colours[i][2];
516 } else if (event == EVENT_VALCHANGE) {
517 if (ctrl == cd->redit || ctrl == cd->gedit || ctrl == cd->bedit) {
518 /* The user has changed the colour using the edit boxes. */
522 dlg_editbox_get(ctrl, dlg, buf, lenof(buf));
523 cval = atoi(buf) & 255;
525 i = dlg_listbox_index(cd->listbox, dlg);
527 if (ctrl == cd->redit)
528 cfg->colours[i][0] = cval;
529 else if (ctrl == cd->gedit)
530 cfg->colours[i][1] = cval;
531 else if (ctrl == cd->bedit)
532 cfg->colours[i][2] = cval;
535 } else if (event == EVENT_ACTION) {
536 if (ctrl == cd->button) {
537 int i = dlg_listbox_index(cd->listbox, dlg);
543 * Start a colour selector, which will send us an
544 * EVENT_CALLBACK when it's finished and allow us to
545 * pick up the results.
547 dlg_coloursel_start(ctrl, dlg,
552 } else if (event == EVENT_CALLBACK) {
553 if (ctrl == cd->button) {
554 int i = dlg_listbox_index(cd->listbox, dlg);
556 * Collect the results of the colour selector. Will
557 * return nonzero on success, or zero if the colour
558 * selector did nothing (user hit Cancel, for example).
560 if (dlg_coloursel_results(ctrl, dlg, &r, &g, &b)) {
561 cfg->colours[i][0] = r;
562 cfg->colours[i][1] = g;
563 cfg->colours[i][2] = b;
571 sprintf(buf, "%d", r); dlg_editbox_set(cd->redit, dlg, buf);
572 sprintf(buf, "%d", g); dlg_editbox_set(cd->gedit, dlg, buf);
573 sprintf(buf, "%d", b); dlg_editbox_set(cd->bedit, dlg, buf);
577 struct environ_data {
578 union control *varbox, *valbox, *addbutton, *rembutton, *listbox;
581 static void environ_handler(union control *ctrl, void *dlg,
582 void *data, int event)
584 Config *cfg = (Config *)data;
585 struct environ_data *ed =
586 (struct environ_data *)ctrl->generic.context.p;
588 if (event == EVENT_REFRESH) {
589 if (ctrl == ed->listbox) {
590 char *p = cfg->environmt;
591 dlg_update_start(ctrl, dlg);
592 dlg_listbox_clear(ctrl, dlg);
594 dlg_listbox_add(ctrl, dlg, p);
597 dlg_update_done(ctrl, dlg);
599 } else if (event == EVENT_ACTION) {
600 if (ctrl == ed->addbutton) {
601 char str[sizeof(cfg->environmt)];
603 dlg_editbox_get(ed->varbox, dlg, str, sizeof(str)-1);
608 p = str + strlen(str);
610 dlg_editbox_get(ed->valbox, dlg, p, sizeof(str)-1 - (p - str));
621 if ((p - cfg->environmt) + strlen(str) + 2 <
622 sizeof(cfg->environmt)) {
624 p[strlen(str) + 1] = '\0';
625 dlg_listbox_add(ed->listbox, dlg, str);
626 dlg_editbox_set(ed->varbox, dlg, "");
627 dlg_editbox_set(ed->valbox, dlg, "");
629 dlg_error_msg(dlg, "Environment too big");
631 } else if (ctrl == ed->rembutton) {
632 int i = dlg_listbox_index(ed->listbox, dlg);
638 dlg_listbox_del(ed->listbox, dlg, i);
666 struct portfwd_data {
667 union control *addbutton, *rembutton, *listbox;
668 union control *sourcebox, *destbox, *direction;
669 union control *addressfamily;
672 static void portfwd_handler(union control *ctrl, void *dlg,
673 void *data, int event)
675 Config *cfg = (Config *)data;
676 struct portfwd_data *pfd =
677 (struct portfwd_data *)ctrl->generic.context.p;
679 if (event == EVENT_REFRESH) {
680 if (ctrl == pfd->listbox) {
681 char *p = cfg->portfwd;
682 dlg_update_start(ctrl, dlg);
683 dlg_listbox_clear(ctrl, dlg);
685 dlg_listbox_add(ctrl, dlg, p);
688 dlg_update_done(ctrl, dlg);
689 } else if (ctrl == pfd->direction) {
693 dlg_radiobutton_set(ctrl, dlg, 0);
694 } else if (ctrl == pfd->addressfamily) {
695 dlg_radiobutton_set(ctrl, dlg, 0);
697 } else if (event == EVENT_ACTION) {
698 if (ctrl == pfd->addbutton) {
699 char str[sizeof(cfg->portfwd)];
705 whichbutton = dlg_radiobutton_get(pfd->addressfamily, dlg);
706 if (whichbutton == 1)
708 else if (whichbutton == 2)
711 whichbutton = dlg_radiobutton_get(pfd->direction, dlg);
712 if (whichbutton == 0)
714 else if (whichbutton == 1)
720 dlg_editbox_get(pfd->sourcebox, dlg, str+i, sizeof(str) - i);
722 dlg_error_msg(dlg, "You need to specify a source port number");
725 p = str + strlen(str);
728 dlg_editbox_get(pfd->destbox, dlg, p,
729 sizeof(str)-1 - (p - str));
730 if (!*p || !strchr(p, ':')) {
732 "You need to specify a destination address\n"
733 "in the form \"host.name:port\"");
744 if ((p - cfg->portfwd) + strlen(str) + 2 <
745 sizeof(cfg->portfwd)) {
747 p[strlen(str) + 1] = '\0';
748 dlg_listbox_add(pfd->listbox, dlg, str);
749 dlg_editbox_set(pfd->sourcebox, dlg, "");
750 dlg_editbox_set(pfd->destbox, dlg, "");
752 dlg_error_msg(dlg, "Too many forwardings");
754 } else if (ctrl == pfd->rembutton) {
755 int i = dlg_listbox_index(pfd->listbox, dlg);
761 dlg_listbox_del(pfd->listbox, dlg, i);
789 void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
790 int midsession, int protocol, int protcfginfo)
792 struct controlset *s;
793 struct sessionsaver_data *ssd;
794 struct charclass_data *ccd;
795 struct colour_data *cd;
796 struct environ_data *ed;
797 struct portfwd_data *pfd;
801 ssd = (struct sessionsaver_data *)
802 ctrl_alloc(b, sizeof(struct sessionsaver_data));
803 memset(ssd, 0, sizeof(*ssd));
804 ssd->midsession = midsession;
807 * The standard panel that appears at the bottom of all panels:
808 * Open, Cancel, Apply etc.
810 s = ctrl_getset(b, "", "", "");
811 ctrl_columns(s, 5, 20, 20, 20, 20, 20);
812 ssd->okbutton = ctrl_pushbutton(s,
813 (midsession ? "Apply" : "Open"),
814 (char)(midsession ? 'a' : 'o'),
816 sessionsaver_handler, P(ssd));
817 ssd->okbutton->button.isdefault = TRUE;
818 ssd->okbutton->generic.column = 3;
819 ssd->cancelbutton = ctrl_pushbutton(s, "Cancel", 'c', HELPCTX(no_help),
820 sessionsaver_handler, P(ssd));
821 ssd->cancelbutton->button.iscancel = TRUE;
822 ssd->cancelbutton->generic.column = 4;
823 /* We carefully don't close the 5-column part, so that platform-
824 * specific add-ons can put extra buttons alongside Open and Cancel. */
829 str = dupprintf("Basic options for your %s session", appname);
830 ctrl_settitle(b, "Session", str);
834 s = ctrl_getset(b, "Session", "hostport",
835 "Specify your connection by host name or IP address");
836 ctrl_columns(s, 2, 75, 25);
837 c = ctrl_editbox(s, "Host Name (or IP address)", 'n', 100,
838 HELPCTX(session_hostname),
839 dlg_stdeditbox_handler, I(offsetof(Config,host)),
840 I(sizeof(((Config *)0)->host)));
841 c->generic.column = 0;
842 c = ctrl_editbox(s, "Port", 'p', 100, HELPCTX(session_hostname),
843 dlg_stdeditbox_handler,
844 I(offsetof(Config,port)), I(-1));
845 c->generic.column = 1;
846 ctrl_columns(s, 1, 100);
847 if (backends[3].name == NULL) {
848 ctrl_radiobuttons(s, "Protocol:", NO_SHORTCUT, 3,
849 HELPCTX(session_hostname),
850 protocolbuttons_handler, P(c),
851 "Raw", 'r', I(PROT_RAW),
852 "Telnet", 't', I(PROT_TELNET),
853 "Rlogin", 'i', I(PROT_RLOGIN),
856 ctrl_radiobuttons(s, "Protocol:", NO_SHORTCUT, 4,
857 HELPCTX(session_hostname),
858 protocolbuttons_handler, P(c),
859 "Raw", 'r', I(PROT_RAW),
860 "Telnet", 't', I(PROT_TELNET),
861 "Rlogin", 'i', I(PROT_RLOGIN),
862 "SSH", 's', I(PROT_SSH),
868 * The Load/Save panel is available even in mid-session.
870 s = ctrl_getset(b, "Session", "savedsessions",
871 "Load, save or delete a stored session");
872 ctrl_columns(s, 2, 75, 25);
873 ssd->sesslist = sesslist;
874 ssd->editbox = ctrl_editbox(s, "Saved Sessions", 'e', 100,
875 HELPCTX(session_saved),
876 sessionsaver_handler, P(ssd), P(NULL));
877 ssd->editbox->generic.column = 0;
878 /* Reset columns so that the buttons are alongside the list, rather
879 * than alongside that edit box. */
880 ctrl_columns(s, 1, 100);
881 ctrl_columns(s, 2, 75, 25);
882 ssd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
883 HELPCTX(session_saved),
884 sessionsaver_handler, P(ssd));
885 ssd->listbox->generic.column = 0;
886 ssd->listbox->listbox.height = 7;
888 ssd->loadbutton = ctrl_pushbutton(s, "Load", 'l',
889 HELPCTX(session_saved),
890 sessionsaver_handler, P(ssd));
891 ssd->loadbutton->generic.column = 1;
893 /* We can't offer the Load button mid-session, as it would allow the
894 * user to load and subsequently save settings they can't see. (And
895 * also change otherwise immutable settings underfoot; that probably
896 * shouldn't be a problem, but.) */
897 ssd->loadbutton = NULL;
899 /* "Save" button is permitted mid-session. */
900 ssd->savebutton = ctrl_pushbutton(s, "Save", 'v',
901 HELPCTX(session_saved),
902 sessionsaver_handler, P(ssd));
903 ssd->savebutton->generic.column = 1;
905 ssd->delbutton = ctrl_pushbutton(s, "Delete", 'd',
906 HELPCTX(session_saved),
907 sessionsaver_handler, P(ssd));
908 ssd->delbutton->generic.column = 1;
910 /* Disable the Delete button mid-session too, for UI consistency. */
911 ssd->delbutton = NULL;
913 ctrl_columns(s, 1, 100);
915 s = ctrl_getset(b, "Session", "otheropts", NULL);
916 c = ctrl_radiobuttons(s, "Close window on exit:", 'w', 4,
917 HELPCTX(session_coe),
918 dlg_stdradiobutton_handler,
919 I(offsetof(Config, close_on_exit)),
920 "Always", I(FORCE_ON),
921 "Never", I(FORCE_OFF),
922 "Only on clean exit", I(AUTO), NULL);
925 * The Session/Logging panel.
927 ctrl_settitle(b, "Session/Logging", "Options controlling session logging");
929 s = ctrl_getset(b, "Session/Logging", "main", NULL);
931 * The logging buttons change depending on whether SSH packet
932 * logging can sensibly be available.
936 if ((midsession && protocol == PROT_SSH) ||
937 (!midsession && backends[3].name != NULL))
938 sshlogname = "Log SSH packet data";
940 sshlogname = NULL; /* this will disable the button */
941 ctrl_radiobuttons(s, "Session logging:", NO_SHORTCUT, 1,
942 HELPCTX(logging_main),
943 dlg_stdradiobutton_handler,
944 I(offsetof(Config, logtype)),
945 "Logging turned off completely", 't', I(LGTYP_NONE),
946 "Log printable output only", 'p', I(LGTYP_ASCII),
947 "Log all session output", 'l', I(LGTYP_DEBUG),
948 sshlogname, 's', I(LGTYP_PACKETS),
951 ctrl_filesel(s, "Log file name:", 'f',
952 NULL, TRUE, "Select session log file name",
953 HELPCTX(logging_filename),
954 dlg_stdfilesel_handler, I(offsetof(Config, logfilename)));
955 ctrl_text(s, "(Log file name can contain &Y, &M, &D for date,"
956 " &T for time, and &H for host name)",
957 HELPCTX(logging_filename));
958 ctrl_radiobuttons(s, "What to do if the log file already exists:", 'e', 1,
959 HELPCTX(logging_exists),
960 dlg_stdradiobutton_handler, I(offsetof(Config,logxfovr)),
961 "Always overwrite it", I(LGXF_OVR),
962 "Always append to the end of it", I(LGXF_APN),
963 "Ask the user every time", I(LGXF_ASK), NULL);
964 ctrl_checkbox(s, "Flush log file frequently", 'u',
965 HELPCTX(logging_flush),
966 dlg_stdcheckbox_handler, I(offsetof(Config,logflush)));
968 if ((midsession && protocol == PROT_SSH) ||
969 (!midsession && backends[3].name != NULL)) {
970 s = ctrl_getset(b, "Session/Logging", "ssh",
971 "Options specific to SSH packet logging");
972 ctrl_checkbox(s, "Omit known password fields", 'k',
973 HELPCTX(logging_ssh_omit_password),
974 dlg_stdcheckbox_handler, I(offsetof(Config,logomitpass)));
975 ctrl_checkbox(s, "Omit session data", 'd',
976 HELPCTX(logging_ssh_omit_data),
977 dlg_stdcheckbox_handler, I(offsetof(Config,logomitdata)));
981 * The Terminal panel.
983 ctrl_settitle(b, "Terminal", "Options controlling the terminal emulation");
985 s = ctrl_getset(b, "Terminal", "general", "Set various terminal options");
986 ctrl_checkbox(s, "Auto wrap mode initially on", 'w',
987 HELPCTX(terminal_autowrap),
988 dlg_stdcheckbox_handler, I(offsetof(Config,wrap_mode)));
989 ctrl_checkbox(s, "DEC Origin Mode initially on", 'd',
990 HELPCTX(terminal_decom),
991 dlg_stdcheckbox_handler, I(offsetof(Config,dec_om)));
992 ctrl_checkbox(s, "Implicit CR in every LF", 'r',
993 HELPCTX(terminal_lfhascr),
994 dlg_stdcheckbox_handler, I(offsetof(Config,lfhascr)));
995 ctrl_checkbox(s, "Use background colour to erase screen", 'e',
996 HELPCTX(terminal_bce),
997 dlg_stdcheckbox_handler, I(offsetof(Config,bce)));
998 ctrl_checkbox(s, "Enable blinking text", 'n',
999 HELPCTX(terminal_blink),
1000 dlg_stdcheckbox_handler, I(offsetof(Config,blinktext)));
1001 ctrl_editbox(s, "Answerback to ^E:", 's', 100,
1002 HELPCTX(terminal_answerback),
1003 dlg_stdeditbox_handler, I(offsetof(Config,answerback)),
1004 I(sizeof(((Config *)0)->answerback)));
1006 s = ctrl_getset(b, "Terminal", "ldisc", "Line discipline options");
1007 ctrl_radiobuttons(s, "Local echo:", 'l', 3,
1008 HELPCTX(terminal_localecho),
1009 dlg_stdradiobutton_handler,I(offsetof(Config,localecho)),
1011 "Force on", I(FORCE_ON),
1012 "Force off", I(FORCE_OFF), NULL);
1013 ctrl_radiobuttons(s, "Local line editing:", 't', 3,
1014 HELPCTX(terminal_localedit),
1015 dlg_stdradiobutton_handler,I(offsetof(Config,localedit)),
1017 "Force on", I(FORCE_ON),
1018 "Force off", I(FORCE_OFF), NULL);
1020 s = ctrl_getset(b, "Terminal", "printing", "Remote-controlled printing");
1021 ctrl_combobox(s, "Printer to send ANSI printer output to:", 'p', 100,
1022 HELPCTX(terminal_printing),
1023 printerbox_handler, P(NULL), P(NULL));
1026 * The Terminal/Keyboard panel.
1028 ctrl_settitle(b, "Terminal/Keyboard",
1029 "Options controlling the effects of keys");
1031 s = ctrl_getset(b, "Terminal/Keyboard", "mappings",
1032 "Change the sequences sent by:");
1033 ctrl_radiobuttons(s, "The Backspace key", 'b', 2,
1034 HELPCTX(keyboard_backspace),
1035 dlg_stdradiobutton_handler,
1036 I(offsetof(Config, bksp_is_delete)),
1037 "Control-H", I(0), "Control-? (127)", I(1), NULL);
1038 ctrl_radiobuttons(s, "The Home and End keys", 'e', 2,
1039 HELPCTX(keyboard_homeend),
1040 dlg_stdradiobutton_handler,
1041 I(offsetof(Config, rxvt_homeend)),
1042 "Standard", I(0), "rxvt", I(1), NULL);
1043 ctrl_radiobuttons(s, "The Function keys and keypad", 'f', 3,
1044 HELPCTX(keyboard_funkeys),
1045 dlg_stdradiobutton_handler,
1046 I(offsetof(Config, funky_type)),
1047 "ESC[n~", I(0), "Linux", I(1), "Xterm R6", I(2),
1048 "VT400", I(3), "VT100+", I(4), "SCO", I(5), NULL);
1050 s = ctrl_getset(b, "Terminal/Keyboard", "appkeypad",
1051 "Application keypad settings:");
1052 ctrl_radiobuttons(s, "Initial state of cursor keys:", 'r', 3,
1053 HELPCTX(keyboard_appcursor),
1054 dlg_stdradiobutton_handler,
1055 I(offsetof(Config, app_cursor)),
1056 "Normal", I(0), "Application", I(1), NULL);
1057 ctrl_radiobuttons(s, "Initial state of numeric keypad:", 'n', 3,
1058 HELPCTX(keyboard_appkeypad),
1059 numeric_keypad_handler, P(NULL),
1060 "Normal", I(0), "Application", I(1), "NetHack", I(2),
1064 * The Terminal/Bell panel.
1066 ctrl_settitle(b, "Terminal/Bell",
1067 "Options controlling the terminal bell");
1069 s = ctrl_getset(b, "Terminal/Bell", "style", "Set the style of bell");
1070 ctrl_radiobuttons(s, "Action to happen when a bell occurs:", 'b', 1,
1071 HELPCTX(bell_style),
1072 dlg_stdradiobutton_handler, I(offsetof(Config, beep)),
1073 "None (bell disabled)", I(BELL_DISABLED),
1074 "Make default system alert sound", I(BELL_DEFAULT),
1075 "Visual bell (flash window)", I(BELL_VISUAL), NULL);
1077 s = ctrl_getset(b, "Terminal/Bell", "overload",
1078 "Control the bell overload behaviour");
1079 ctrl_checkbox(s, "Bell is temporarily disabled when over-used", 'd',
1080 HELPCTX(bell_overload),
1081 dlg_stdcheckbox_handler, I(offsetof(Config,bellovl)));
1082 ctrl_editbox(s, "Over-use means this many bells...", 'm', 20,
1083 HELPCTX(bell_overload),
1084 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_n)), I(-1));
1085 ctrl_editbox(s, "... in this many seconds", 't', 20,
1086 HELPCTX(bell_overload),
1087 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_t)),
1089 ctrl_text(s, "The bell is re-enabled after a few seconds of silence.",
1090 HELPCTX(bell_overload));
1091 ctrl_editbox(s, "Seconds of silence required", 's', 20,
1092 HELPCTX(bell_overload),
1093 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_s)),
1097 * The Terminal/Features panel.
1099 ctrl_settitle(b, "Terminal/Features",
1100 "Enabling and disabling advanced terminal features");
1102 s = ctrl_getset(b, "Terminal/Features", "main", NULL);
1103 ctrl_checkbox(s, "Disable application cursor keys mode", 'u',
1104 HELPCTX(features_application),
1105 dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_c)));
1106 ctrl_checkbox(s, "Disable application keypad mode", 'k',
1107 HELPCTX(features_application),
1108 dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_k)));
1109 ctrl_checkbox(s, "Disable xterm-style mouse reporting", 'x',
1110 HELPCTX(features_mouse),
1111 dlg_stdcheckbox_handler, I(offsetof(Config,no_mouse_rep)));
1112 ctrl_checkbox(s, "Disable remote-controlled terminal resizing", 's',
1113 HELPCTX(features_resize),
1114 dlg_stdcheckbox_handler,
1115 I(offsetof(Config,no_remote_resize)));
1116 ctrl_checkbox(s, "Disable switching to alternate terminal screen", 'w',
1117 HELPCTX(features_altscreen),
1118 dlg_stdcheckbox_handler, I(offsetof(Config,no_alt_screen)));
1119 ctrl_checkbox(s, "Disable remote-controlled window title changing", 't',
1120 HELPCTX(features_retitle),
1121 dlg_stdcheckbox_handler,
1122 I(offsetof(Config,no_remote_wintitle)));
1123 ctrl_checkbox(s, "Disable remote window title querying (SECURITY)",
1124 'q', HELPCTX(features_qtitle), dlg_stdcheckbox_handler,
1125 I(offsetof(Config,no_remote_qtitle)));
1126 ctrl_checkbox(s, "Disable destructive backspace on server sending ^?",'b',
1127 HELPCTX(features_dbackspace),
1128 dlg_stdcheckbox_handler, I(offsetof(Config,no_dbackspace)));
1129 ctrl_checkbox(s, "Disable remote-controlled character set configuration",
1130 'r', HELPCTX(features_charset), dlg_stdcheckbox_handler,
1131 I(offsetof(Config,no_remote_charset)));
1132 ctrl_checkbox(s, "Disable Arabic text shaping",
1133 'l', HELPCTX(features_arabicshaping), dlg_stdcheckbox_handler,
1134 I(offsetof(Config, arabicshaping)));
1135 ctrl_checkbox(s, "Disable bidirectional text display",
1136 'd', HELPCTX(features_bidi), dlg_stdcheckbox_handler,
1137 I(offsetof(Config, bidi)));
1142 str = dupprintf("Options controlling %s's window", appname);
1143 ctrl_settitle(b, "Window", str);
1146 s = ctrl_getset(b, "Window", "size", "Set the size of the window");
1147 ctrl_columns(s, 2, 50, 50);
1148 c = ctrl_editbox(s, "Rows", 'r', 100,
1149 HELPCTX(window_size),
1150 dlg_stdeditbox_handler, I(offsetof(Config,height)),I(-1));
1151 c->generic.column = 0;
1152 c = ctrl_editbox(s, "Columns", 'm', 100,
1153 HELPCTX(window_size),
1154 dlg_stdeditbox_handler, I(offsetof(Config,width)), I(-1));
1155 c->generic.column = 1;
1156 ctrl_columns(s, 1, 100);
1158 s = ctrl_getset(b, "Window", "scrollback",
1159 "Control the scrollback in the window");
1160 ctrl_editbox(s, "Lines of scrollback", 's', 50,
1161 HELPCTX(window_scrollback),
1162 dlg_stdeditbox_handler, I(offsetof(Config,savelines)), I(-1));
1163 ctrl_checkbox(s, "Display scrollbar", 'd',
1164 HELPCTX(window_scrollback),
1165 dlg_stdcheckbox_handler, I(offsetof(Config,scrollbar)));
1166 ctrl_checkbox(s, "Reset scrollback on keypress", 'k',
1167 HELPCTX(window_scrollback),
1168 dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_key)));
1169 ctrl_checkbox(s, "Reset scrollback on display activity", 'p',
1170 HELPCTX(window_scrollback),
1171 dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_disp)));
1172 ctrl_checkbox(s, "Push erased text into scrollback", 'e',
1173 HELPCTX(window_erased),
1174 dlg_stdcheckbox_handler,
1175 I(offsetof(Config,erase_to_scrollback)));
1178 * The Window/Appearance panel.
1180 str = dupprintf("Configure the appearance of %s's window", appname);
1181 ctrl_settitle(b, "Window/Appearance", str);
1184 s = ctrl_getset(b, "Window/Appearance", "cursor",
1185 "Adjust the use of the cursor");
1186 ctrl_radiobuttons(s, "Cursor appearance:", NO_SHORTCUT, 3,
1187 HELPCTX(appearance_cursor),
1188 dlg_stdradiobutton_handler,
1189 I(offsetof(Config, cursor_type)),
1191 "Underline", 'u', I(1),
1192 "Vertical line", 'v', I(2), NULL);
1193 ctrl_checkbox(s, "Cursor blinks", 'b',
1194 HELPCTX(appearance_cursor),
1195 dlg_stdcheckbox_handler, I(offsetof(Config,blink_cur)));
1197 s = ctrl_getset(b, "Window/Appearance", "font",
1199 ctrl_fontsel(s, "Font used in the terminal window", 'n',
1200 HELPCTX(appearance_font),
1201 dlg_stdfontsel_handler, I(offsetof(Config, font)));
1203 s = ctrl_getset(b, "Window/Appearance", "mouse",
1204 "Adjust the use of the mouse pointer");
1205 ctrl_checkbox(s, "Hide mouse pointer when typing in window", 'p',
1206 HELPCTX(appearance_hidemouse),
1207 dlg_stdcheckbox_handler, I(offsetof(Config,hide_mouseptr)));
1209 s = ctrl_getset(b, "Window/Appearance", "border",
1210 "Adjust the window border");
1211 ctrl_editbox(s, "Gap between text and window edge:", NO_SHORTCUT, 20,
1212 HELPCTX(appearance_border),
1213 dlg_stdeditbox_handler,
1214 I(offsetof(Config,window_border)), I(-1));
1217 * The Window/Behaviour panel.
1219 str = dupprintf("Configure the behaviour of %s's window", appname);
1220 ctrl_settitle(b, "Window/Behaviour", str);
1223 s = ctrl_getset(b, "Window/Behaviour", "title",
1224 "Adjust the behaviour of the window title");
1225 ctrl_editbox(s, "Window title:", 't', 100,
1226 HELPCTX(appearance_title),
1227 dlg_stdeditbox_handler, I(offsetof(Config,wintitle)),
1228 I(sizeof(((Config *)0)->wintitle)));
1229 ctrl_checkbox(s, "Separate window and icon titles", 'i',
1230 HELPCTX(appearance_title),
1231 dlg_stdcheckbox_handler,
1232 I(CHECKBOX_INVERT | offsetof(Config,win_name_always)));
1234 s = ctrl_getset(b, "Window/Behaviour", "main", NULL);
1235 ctrl_checkbox(s, "Warn before closing window", 'w',
1236 HELPCTX(behaviour_closewarn),
1237 dlg_stdcheckbox_handler, I(offsetof(Config,warn_on_close)));
1240 * The Window/Translation panel.
1242 ctrl_settitle(b, "Window/Translation",
1243 "Options controlling character set translation");
1245 s = ctrl_getset(b, "Window/Translation", "trans",
1246 "Character set translation on received data");
1247 ctrl_combobox(s, "Received data assumed to be in which character set:",
1248 'r', 100, HELPCTX(translation_codepage),
1249 codepage_handler, P(NULL), P(NULL));
1251 str = dupprintf("Adjust how %s handles line drawing characters", appname);
1252 s = ctrl_getset(b, "Window/Translation", "linedraw", str);
1254 ctrl_radiobuttons(s, "Handling of line drawing characters:", NO_SHORTCUT,1,
1255 HELPCTX(translation_linedraw),
1256 dlg_stdradiobutton_handler,
1257 I(offsetof(Config, vtmode)),
1258 "Use Unicode line drawing code points",'u',I(VT_UNICODE),
1259 "Poor man's line drawing (+, - and |)",'p',I(VT_POORMAN),
1261 ctrl_checkbox(s, "Copy and paste line drawing characters as lqqqk",'d',
1262 HELPCTX(selection_linedraw),
1263 dlg_stdcheckbox_handler, I(offsetof(Config,rawcnp)));
1266 * The Window/Selection panel.
1268 ctrl_settitle(b, "Window/Selection", "Options controlling copy and paste");
1270 s = ctrl_getset(b, "Window/Selection", "mouse",
1271 "Control use of mouse");
1272 ctrl_checkbox(s, "Shift overrides application's use of mouse", 'p',
1273 HELPCTX(selection_shiftdrag),
1274 dlg_stdcheckbox_handler, I(offsetof(Config,mouse_override)));
1275 ctrl_radiobuttons(s,
1276 "Default selection mode (Alt+drag does the other one):",
1278 HELPCTX(selection_rect),
1279 dlg_stdradiobutton_handler,
1280 I(offsetof(Config, rect_select)),
1281 "Normal", 'n', I(0),
1282 "Rectangular block", 'r', I(1), NULL);
1284 s = ctrl_getset(b, "Window/Selection", "charclass",
1285 "Control the select-one-word-at-a-time mode");
1286 ccd = (struct charclass_data *)
1287 ctrl_alloc(b, sizeof(struct charclass_data));
1288 ccd->listbox = ctrl_listbox(s, "Character classes:", 'e',
1289 HELPCTX(selection_charclasses),
1290 charclass_handler, P(ccd));
1291 ccd->listbox->listbox.multisel = 1;
1292 ccd->listbox->listbox.ncols = 4;
1293 ccd->listbox->listbox.percentages = snewn(4, int);
1294 ccd->listbox->listbox.percentages[0] = 15;
1295 ccd->listbox->listbox.percentages[1] = 25;
1296 ccd->listbox->listbox.percentages[2] = 20;
1297 ccd->listbox->listbox.percentages[3] = 40;
1298 ctrl_columns(s, 2, 67, 33);
1299 ccd->editbox = ctrl_editbox(s, "Set to class", 't', 50,
1300 HELPCTX(selection_charclasses),
1301 charclass_handler, P(ccd), P(NULL));
1302 ccd->editbox->generic.column = 0;
1303 ccd->button = ctrl_pushbutton(s, "Set", 's',
1304 HELPCTX(selection_charclasses),
1305 charclass_handler, P(ccd));
1306 ccd->button->generic.column = 1;
1307 ctrl_columns(s, 1, 100);
1310 * The Window/Colours panel.
1312 ctrl_settitle(b, "Window/Colours", "Options controlling use of colours");
1314 s = ctrl_getset(b, "Window/Colours", "general",
1315 "General options for colour usage");
1316 ctrl_checkbox(s, "Allow terminal to specify ANSI colours", 'i',
1317 HELPCTX(colours_ansi),
1318 dlg_stdcheckbox_handler, I(offsetof(Config,ansi_colour)));
1319 ctrl_checkbox(s, "Allow terminal to use xterm 256-colour mode", '2',
1320 HELPCTX(colours_xterm256), dlg_stdcheckbox_handler,
1321 I(offsetof(Config,xterm_256_colour)));
1322 ctrl_checkbox(s, "Bolded text is a different colour", 'b',
1323 HELPCTX(colours_bold),
1324 dlg_stdcheckbox_handler, I(offsetof(Config,bold_colour)));
1326 str = dupprintf("Adjust the precise colours %s displays", appname);
1327 s = ctrl_getset(b, "Window/Colours", "adjust", str);
1329 ctrl_text(s, "Select a colour from the list, and then click the"
1330 " Modify button to change its appearance.",
1331 HELPCTX(colours_config));
1332 ctrl_columns(s, 2, 67, 33);
1333 cd = (struct colour_data *)ctrl_alloc(b, sizeof(struct colour_data));
1334 cd->listbox = ctrl_listbox(s, "Select a colour to adjust:", 'u',
1335 HELPCTX(colours_config), colour_handler, P(cd));
1336 cd->listbox->generic.column = 0;
1337 cd->listbox->listbox.height = 7;
1338 c = ctrl_text(s, "RGB value:", HELPCTX(colours_config));
1339 c->generic.column = 1;
1340 cd->redit = ctrl_editbox(s, "Red", 'r', 50, HELPCTX(colours_config),
1341 colour_handler, P(cd), P(NULL));
1342 cd->redit->generic.column = 1;
1343 cd->gedit = ctrl_editbox(s, "Green", 'n', 50, HELPCTX(colours_config),
1344 colour_handler, P(cd), P(NULL));
1345 cd->gedit->generic.column = 1;
1346 cd->bedit = ctrl_editbox(s, "Blue", 'e', 50, HELPCTX(colours_config),
1347 colour_handler, P(cd), P(NULL));
1348 cd->bedit->generic.column = 1;
1349 cd->button = ctrl_pushbutton(s, "Modify", 'm', HELPCTX(colours_config),
1350 colour_handler, P(cd));
1351 cd->button->generic.column = 1;
1352 ctrl_columns(s, 1, 100);
1355 * The Connection panel. This doesn't show up if we're in a
1356 * non-network utility such as pterm. We tell this by being
1357 * passed a protocol < 0.
1359 if (protocol >= 0) {
1360 ctrl_settitle(b, "Connection", "Options controlling the connection");
1362 s = ctrl_getset(b, "Connection", "keepalive",
1363 "Sending of null packets to keep session active");
1364 ctrl_editbox(s, "Seconds between keepalives (0 to turn off)", 'k', 20,
1365 HELPCTX(connection_keepalive),
1366 dlg_stdeditbox_handler, I(offsetof(Config,ping_interval)),
1370 s = ctrl_getset(b, "Connection", "tcp",
1371 "Low-level TCP connection options");
1372 ctrl_checkbox(s, "Disable Nagle's algorithm (TCP_NODELAY option)",
1373 'n', HELPCTX(connection_nodelay),
1374 dlg_stdcheckbox_handler,
1375 I(offsetof(Config,tcp_nodelay)));
1376 ctrl_checkbox(s, "Enable TCP keepalives (SO_KEEPALIVE option)",
1377 'p', HELPCTX(connection_tcpkeepalive),
1378 dlg_stdcheckbox_handler,
1379 I(offsetof(Config,tcp_keepalives)));
1380 s = ctrl_getset(b, "Connection", "ipversion",
1381 "Internet protocol version");
1382 ctrl_radiobuttons(s, NULL, NO_SHORTCUT,
1388 HELPCTX(connection_ipversion),
1389 dlg_stdradiobutton_handler,
1390 I(offsetof(Config, addressfamily)),
1391 "Auto", NO_SHORTCUT, I(ADDRTYPE_UNSPEC),
1392 "IPv4", NO_SHORTCUT, I(ADDRTYPE_IPV4),
1394 "IPv6", NO_SHORTCUT, I(ADDRTYPE_IPV6),
1400 * A sub-panel Connection/Data, containing options that
1401 * decide on data to send to the server.
1404 ctrl_settitle(b, "Connection/Data", "Data to send to the server");
1406 s = ctrl_getset(b, "Connection/Data", "login",
1408 ctrl_editbox(s, "Auto-login username", 'u', 50,
1409 HELPCTX(connection_username),
1410 dlg_stdeditbox_handler, I(offsetof(Config,username)),
1411 I(sizeof(((Config *)0)->username)));
1413 s = ctrl_getset(b, "Connection/Data", "term",
1414 "Terminal details");
1415 ctrl_editbox(s, "Terminal-type string", 't', 50,
1416 HELPCTX(connection_termtype),
1417 dlg_stdeditbox_handler, I(offsetof(Config,termtype)),
1418 I(sizeof(((Config *)0)->termtype)));
1419 ctrl_editbox(s, "Terminal speeds", 's', 50,
1420 HELPCTX(connection_termspeed),
1421 dlg_stdeditbox_handler, I(offsetof(Config,termspeed)),
1422 I(sizeof(((Config *)0)->termspeed)));
1424 s = ctrl_getset(b, "Connection/Data", "env",
1425 "Environment variables");
1426 ctrl_columns(s, 2, 80, 20);
1427 ed = (struct environ_data *)
1428 ctrl_alloc(b, sizeof(struct environ_data));
1429 ed->varbox = ctrl_editbox(s, "Variable", 'v', 60,
1430 HELPCTX(telnet_environ),
1431 environ_handler, P(ed), P(NULL));
1432 ed->varbox->generic.column = 0;
1433 ed->valbox = ctrl_editbox(s, "Value", 'l', 60,
1434 HELPCTX(telnet_environ),
1435 environ_handler, P(ed), P(NULL));
1436 ed->valbox->generic.column = 0;
1437 ed->addbutton = ctrl_pushbutton(s, "Add", 'd',
1438 HELPCTX(telnet_environ),
1439 environ_handler, P(ed));
1440 ed->addbutton->generic.column = 1;
1441 ed->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1442 HELPCTX(telnet_environ),
1443 environ_handler, P(ed));
1444 ed->rembutton->generic.column = 1;
1445 ctrl_columns(s, 1, 100);
1446 ed->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1447 HELPCTX(telnet_environ),
1448 environ_handler, P(ed));
1449 ed->listbox->listbox.height = 3;
1450 ed->listbox->listbox.ncols = 2;
1451 ed->listbox->listbox.percentages = snewn(2, int);
1452 ed->listbox->listbox.percentages[0] = 30;
1453 ed->listbox->listbox.percentages[1] = 70;
1460 * The Connection/Proxy panel.
1462 ctrl_settitle(b, "Connection/Proxy",
1463 "Options controlling proxy usage");
1465 s = ctrl_getset(b, "Connection/Proxy", "basics", NULL);
1466 ctrl_radiobuttons(s, "Proxy type:", 't', 3,
1467 HELPCTX(proxy_type),
1468 dlg_stdradiobutton_handler,
1469 I(offsetof(Config, proxy_type)),
1470 "None", I(PROXY_NONE),
1471 "SOCKS 4", I(PROXY_SOCKS4),
1472 "SOCKS 5", I(PROXY_SOCKS5),
1473 "HTTP", I(PROXY_HTTP),
1474 "Telnet", I(PROXY_TELNET),
1476 ctrl_columns(s, 2, 80, 20);
1477 c = ctrl_editbox(s, "Proxy hostname", 'y', 100,
1478 HELPCTX(proxy_main),
1479 dlg_stdeditbox_handler,
1480 I(offsetof(Config,proxy_host)),
1481 I(sizeof(((Config *)0)->proxy_host)));
1482 c->generic.column = 0;
1483 c = ctrl_editbox(s, "Port", 'p', 100,
1484 HELPCTX(proxy_main),
1485 dlg_stdeditbox_handler,
1486 I(offsetof(Config,proxy_port)),
1488 c->generic.column = 1;
1489 ctrl_columns(s, 1, 100);
1490 ctrl_editbox(s, "Exclude Hosts/IPs", 'e', 100,
1491 HELPCTX(proxy_exclude),
1492 dlg_stdeditbox_handler,
1493 I(offsetof(Config,proxy_exclude_list)),
1494 I(sizeof(((Config *)0)->proxy_exclude_list)));
1495 ctrl_checkbox(s, "Consider proxying local host connections", 'x',
1496 HELPCTX(proxy_exclude),
1497 dlg_stdcheckbox_handler,
1498 I(offsetof(Config,even_proxy_localhost)));
1499 ctrl_radiobuttons(s, "Do DNS name lookup at proxy end:", 'd', 3,
1501 dlg_stdradiobutton_handler,
1502 I(offsetof(Config, proxy_dns)),
1505 "Yes", I(FORCE_ON), NULL);
1506 ctrl_editbox(s, "Username", 'u', 60,
1507 HELPCTX(proxy_auth),
1508 dlg_stdeditbox_handler,
1509 I(offsetof(Config,proxy_username)),
1510 I(sizeof(((Config *)0)->proxy_username)));
1511 c = ctrl_editbox(s, "Password", 'w', 60,
1512 HELPCTX(proxy_auth),
1513 dlg_stdeditbox_handler,
1514 I(offsetof(Config,proxy_password)),
1515 I(sizeof(((Config *)0)->proxy_password)));
1516 c->editbox.password = 1;
1517 ctrl_editbox(s, "Telnet command", 'm', 100,
1518 HELPCTX(proxy_command),
1519 dlg_stdeditbox_handler,
1520 I(offsetof(Config,proxy_telnet_command)),
1521 I(sizeof(((Config *)0)->proxy_telnet_command)));
1525 * The Telnet panel exists in the base config box, and in a
1526 * mid-session reconfig box _if_ we're using Telnet.
1528 if (!midsession || protocol == PROT_TELNET) {
1530 * The Connection/Telnet panel.
1532 ctrl_settitle(b, "Connection/Telnet",
1533 "Options controlling Telnet connections");
1535 s = ctrl_getset(b, "Connection/Telnet", "protocol",
1536 "Telnet protocol adjustments");
1539 ctrl_radiobuttons(s, "Handling of OLD_ENVIRON ambiguity:",
1541 HELPCTX(telnet_oldenviron),
1542 dlg_stdradiobutton_handler,
1543 I(offsetof(Config, rfc_environ)),
1544 "BSD (commonplace)", 'b', I(0),
1545 "RFC 1408 (unusual)", 'f', I(1), NULL);
1546 ctrl_radiobuttons(s, "Telnet negotiation mode:", 't', 2,
1547 HELPCTX(telnet_passive),
1548 dlg_stdradiobutton_handler,
1549 I(offsetof(Config, passive_telnet)),
1550 "Passive", I(1), "Active", I(0), NULL);
1552 ctrl_checkbox(s, "Keyboard sends Telnet special commands", 'k',
1553 HELPCTX(telnet_specialkeys),
1554 dlg_stdcheckbox_handler,
1555 I(offsetof(Config,telnet_keyboard)));
1556 ctrl_checkbox(s, "Return key sends Telnet New Line instead of ^M",
1557 'm', HELPCTX(telnet_newline),
1558 dlg_stdcheckbox_handler,
1559 I(offsetof(Config,telnet_newline)));
1565 * The Connection/Rlogin panel.
1567 ctrl_settitle(b, "Connection/Rlogin",
1568 "Options controlling Rlogin connections");
1570 s = ctrl_getset(b, "Connection/Rlogin", "data",
1571 "Data to send to the server");
1572 ctrl_editbox(s, "Local username:", 'l', 50,
1573 HELPCTX(rlogin_localuser),
1574 dlg_stdeditbox_handler, I(offsetof(Config,localusername)),
1575 I(sizeof(((Config *)0)->localusername)));
1580 * All the SSH stuff is omitted in PuTTYtel, or in a reconfig
1581 * when we're not doing SSH.
1584 if (backends[3].name != NULL && (!midsession || protocol == PROT_SSH)) {
1587 * The Connection/SSH panel.
1589 ctrl_settitle(b, "Connection/SSH",
1590 "Options controlling SSH connections");
1593 s = ctrl_getset(b, "Connection/SSH", "disclaimer", NULL);
1594 ctrl_text(s, "Nothing on this panel may be reconfigured in mid-"
1595 "session; it is only here so that sub-panels of it can "
1596 "exist without looking strange.", HELPCTX(no_help));
1601 s = ctrl_getset(b, "Connection/SSH", "data",
1602 "Data to send to the server");
1603 ctrl_editbox(s, "Remote command:", 'r', 100,
1604 HELPCTX(ssh_command),
1605 dlg_stdeditbox_handler, I(offsetof(Config,remote_cmd)),
1606 I(sizeof(((Config *)0)->remote_cmd)));
1608 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1609 ctrl_checkbox(s, "Don't allocate a pseudo-terminal", 'p',
1611 dlg_stdcheckbox_handler,
1612 I(offsetof(Config,nopty)));
1613 ctrl_checkbox(s, "Don't start a shell or command at all", 'n',
1614 HELPCTX(ssh_noshell),
1615 dlg_stdcheckbox_handler,
1616 I(offsetof(Config,ssh_no_shell)));
1617 ctrl_checkbox(s, "Enable compression", 'e',
1618 HELPCTX(ssh_compress),
1619 dlg_stdcheckbox_handler,
1620 I(offsetof(Config,compression)));
1621 ctrl_radiobuttons(s, "Preferred SSH protocol version:", NO_SHORTCUT, 4,
1622 HELPCTX(ssh_protocol),
1623 dlg_stdradiobutton_handler,
1624 I(offsetof(Config, sshprot)),
1625 "1 only", 'l', I(0),
1628 "2 only", 'y', I(3), NULL);
1630 s = ctrl_getset(b, "Connection/SSH", "encryption", "Encryption options");
1631 c = ctrl_draglist(s, "Encryption cipher selection policy:", 's',
1632 HELPCTX(ssh_ciphers),
1633 cipherlist_handler, P(NULL));
1634 c->listbox.height = 6;
1636 ctrl_checkbox(s, "Enable legacy use of single-DES in SSH 2", 'i',
1637 HELPCTX(ssh_ciphers),
1638 dlg_stdcheckbox_handler,
1639 I(offsetof(Config,ssh2_des_cbc)));
1643 * The Connection/SSH/Kex panel. (Owing to repeat key
1644 * exchange, this is all meaningful in mid-session _if_
1645 * we're using SSH2 or haven't decided yet.)
1647 if (protcfginfo != 1) {
1648 ctrl_settitle(b, "Connection/SSH/Kex",
1649 "Options controlling SSH key exchange");
1651 s = ctrl_getset(b, "Connection/SSH/Kex", "main",
1652 "Key exchange algorithm options");
1653 c = ctrl_draglist(s, "Algorithm selection policy", 's',
1654 HELPCTX(ssh_kexlist),
1655 kexlist_handler, P(NULL));
1656 c->listbox.height = 5;
1658 s = ctrl_getset(b, "Connection/SSH/Kex", "repeat",
1659 "Options controlling key re-exchange");
1661 ctrl_editbox(s, "Max minutes before rekey (0 for no limit)", 't', 20,
1662 HELPCTX(ssh_kex_repeat),
1663 dlg_stdeditbox_handler,
1664 I(offsetof(Config,ssh_rekey_time)),
1666 ctrl_editbox(s, "Max data before rekey (0 for no limit)", 'x', 20,
1667 HELPCTX(ssh_kex_repeat),
1668 dlg_stdeditbox_handler,
1669 I(offsetof(Config,ssh_rekey_data)),
1671 ctrl_text(s, "(Use 1M for 1 megabyte, 1G for 1 gigabyte etc)",
1672 HELPCTX(ssh_kex_repeat));
1678 * The Connection/SSH/Auth panel.
1680 ctrl_settitle(b, "Connection/SSH/Auth",
1681 "Options controlling SSH authentication");
1683 s = ctrl_getset(b, "Connection/SSH/Auth", "methods",
1684 "Authentication methods");
1685 ctrl_checkbox(s, "Attempt TIS or CryptoCard auth (SSH1)", 'm',
1686 HELPCTX(ssh_auth_tis),
1687 dlg_stdcheckbox_handler,
1688 I(offsetof(Config,try_tis_auth)));
1689 ctrl_checkbox(s, "Attempt \"keyboard-interactive\" auth (SSH2)",
1690 'i', HELPCTX(ssh_auth_ki),
1691 dlg_stdcheckbox_handler,
1692 I(offsetof(Config,try_ki_auth)));
1694 s = ctrl_getset(b, "Connection/SSH/Auth", "params",
1695 "Authentication parameters");
1696 ctrl_checkbox(s, "Allow agent forwarding", 'f',
1697 HELPCTX(ssh_auth_agentfwd),
1698 dlg_stdcheckbox_handler, I(offsetof(Config,agentfwd)));
1699 ctrl_checkbox(s, "Allow attempted changes of username in SSH2", 'u',
1700 HELPCTX(ssh_auth_changeuser),
1701 dlg_stdcheckbox_handler,
1702 I(offsetof(Config,change_username)));
1703 ctrl_filesel(s, "Private key file for authentication:", 'k',
1704 FILTER_KEY_FILES, FALSE, "Select private key file",
1705 HELPCTX(ssh_auth_privkey),
1706 dlg_stdfilesel_handler, I(offsetof(Config, keyfile)));
1711 * The Connection/SSH/X11 panel.
1713 ctrl_settitle(b, "Connection/SSH/X11",
1714 "Options controlling SSH X11 forwarding");
1716 s = ctrl_getset(b, "Connection/SSH/X11", "x11", "X11 forwarding");
1717 ctrl_checkbox(s, "Enable X11 forwarding", 'e',
1718 HELPCTX(ssh_tunnels_x11),
1719 dlg_stdcheckbox_handler,I(offsetof(Config,x11_forward)));
1720 ctrl_editbox(s, "X display location", 'x', 50,
1721 HELPCTX(ssh_tunnels_x11),
1722 dlg_stdeditbox_handler, I(offsetof(Config,x11_display)),
1723 I(sizeof(((Config *)0)->x11_display)));
1724 ctrl_radiobuttons(s, "Remote X11 authentication protocol", 'u', 2,
1725 HELPCTX(ssh_tunnels_x11auth),
1726 dlg_stdradiobutton_handler,
1727 I(offsetof(Config, x11_auth)),
1728 "MIT-Magic-Cookie-1", I(X11_MIT),
1729 "XDM-Authorization-1", I(X11_XDM), NULL);
1733 * The Tunnels panel _is_ still available in mid-session.
1735 ctrl_settitle(b, "Connection/SSH/Tunnels",
1736 "Options controlling SSH port forwarding");
1738 s = ctrl_getset(b, "Connection/SSH/Tunnels", "portfwd",
1740 ctrl_checkbox(s, "Local ports accept connections from other hosts",'t',
1741 HELPCTX(ssh_tunnels_portfwd_localhost),
1742 dlg_stdcheckbox_handler,
1743 I(offsetof(Config,lport_acceptall)));
1744 ctrl_checkbox(s, "Remote ports do the same (SSH v2 only)", 'p',
1745 HELPCTX(ssh_tunnels_portfwd_localhost),
1746 dlg_stdcheckbox_handler,
1747 I(offsetof(Config,rport_acceptall)));
1749 ctrl_columns(s, 3, 55, 20, 25);
1750 c = ctrl_text(s, "Forwarded ports:", HELPCTX(ssh_tunnels_portfwd));
1751 c->generic.column = COLUMN_FIELD(0,2);
1752 /* You want to select from the list, _then_ hit Remove. So tab order
1753 * should be that way round. */
1754 pfd = (struct portfwd_data *)ctrl_alloc(b,sizeof(struct portfwd_data));
1755 pfd->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1756 HELPCTX(ssh_tunnels_portfwd),
1757 portfwd_handler, P(pfd));
1758 pfd->rembutton->generic.column = 2;
1759 pfd->rembutton->generic.tabdelay = 1;
1760 pfd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1761 HELPCTX(ssh_tunnels_portfwd),
1762 portfwd_handler, P(pfd));
1763 pfd->listbox->listbox.height = 3;
1764 pfd->listbox->listbox.ncols = 2;
1765 pfd->listbox->listbox.percentages = snewn(2, int);
1766 pfd->listbox->listbox.percentages[0] = 20;
1767 pfd->listbox->listbox.percentages[1] = 80;
1768 ctrl_tabdelay(s, pfd->rembutton);
1769 ctrl_text(s, "Add new forwarded port:", HELPCTX(ssh_tunnels_portfwd));
1770 /* You want to enter source, destination and type, _then_ hit Add.
1771 * Again, we adjust the tab order to reflect this. */
1772 pfd->addbutton = ctrl_pushbutton(s, "Add", 'd',
1773 HELPCTX(ssh_tunnels_portfwd),
1774 portfwd_handler, P(pfd));
1775 pfd->addbutton->generic.column = 2;
1776 pfd->addbutton->generic.tabdelay = 1;
1777 pfd->sourcebox = ctrl_editbox(s, "Source port", 's', 40,
1778 HELPCTX(ssh_tunnels_portfwd),
1779 portfwd_handler, P(pfd), P(NULL));
1780 pfd->sourcebox->generic.column = 0;
1781 pfd->destbox = ctrl_editbox(s, "Destination", 'i', 67,
1782 HELPCTX(ssh_tunnels_portfwd),
1783 portfwd_handler, P(pfd), P(NULL));
1784 pfd->direction = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
1785 HELPCTX(ssh_tunnels_portfwd),
1786 portfwd_handler, P(pfd),
1787 "Local", 'l', P(NULL),
1788 "Remote", 'm', P(NULL),
1789 "Dynamic", 'y', P(NULL),
1791 pfd->addressfamily =
1792 ctrl_radiobuttons(s, NULL, NO_SHORTCUT,
1798 HELPCTX(ssh_tunnels_portfwd_ipversion),
1799 portfwd_handler, P(pfd),
1800 "Auto", NO_SHORTCUT, I(ADDRTYPE_UNSPEC),
1801 "IPv4", NO_SHORTCUT, I(ADDRTYPE_IPV4),
1803 "IPv6", NO_SHORTCUT, I(ADDRTYPE_IPV6),
1806 ctrl_tabdelay(s, pfd->addbutton);
1807 ctrl_columns(s, 1, 100);
1811 * The Connection/SSH/Bugs panel.
1813 ctrl_settitle(b, "Connection/SSH/Bugs",
1814 "Workarounds for SSH server bugs");
1816 s = ctrl_getset(b, "Connection/SSH/Bugs", "main",
1817 "Detection of known bugs in SSH servers");
1818 ctrl_droplist(s, "Chokes on SSH1 ignore messages", 'i', 20,
1819 HELPCTX(ssh_bugs_ignore1),
1820 sshbug_handler, I(offsetof(Config,sshbug_ignore1)));
1821 ctrl_droplist(s, "Refuses all SSH1 password camouflage", 's', 20,
1822 HELPCTX(ssh_bugs_plainpw1),
1823 sshbug_handler, I(offsetof(Config,sshbug_plainpw1)));
1824 ctrl_droplist(s, "Chokes on SSH1 RSA authentication", 'r', 20,
1825 HELPCTX(ssh_bugs_rsa1),
1826 sshbug_handler, I(offsetof(Config,sshbug_rsa1)));
1827 ctrl_droplist(s, "Miscomputes SSH2 HMAC keys", 'm', 20,
1828 HELPCTX(ssh_bugs_hmac2),
1829 sshbug_handler, I(offsetof(Config,sshbug_hmac2)));
1830 ctrl_droplist(s, "Miscomputes SSH2 encryption keys", 'e', 20,
1831 HELPCTX(ssh_bugs_derivekey2),
1832 sshbug_handler, I(offsetof(Config,sshbug_derivekey2)));
1833 ctrl_droplist(s, "Requires padding on SSH2 RSA signatures", 'p', 20,
1834 HELPCTX(ssh_bugs_rsapad2),
1835 sshbug_handler, I(offsetof(Config,sshbug_rsapad2)));
1836 ctrl_droplist(s, "Misuses the session ID in PK auth", 'n', 20,
1837 HELPCTX(ssh_bugs_pksessid2),
1838 sshbug_handler, I(offsetof(Config,sshbug_pksessid2)));