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 midsession ? "Save the current session settings" :
872 "Load, save or delete a stored session");
873 ctrl_columns(s, 2, 75, 25);
874 ssd->sesslist = sesslist;
875 ssd->editbox = ctrl_editbox(s, "Saved Sessions", 'e', 100,
876 HELPCTX(session_saved),
877 sessionsaver_handler, P(ssd), P(NULL));
878 ssd->editbox->generic.column = 0;
879 /* Reset columns so that the buttons are alongside the list, rather
880 * than alongside that edit box. */
881 ctrl_columns(s, 1, 100);
882 ctrl_columns(s, 2, 75, 25);
883 ssd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
884 HELPCTX(session_saved),
885 sessionsaver_handler, P(ssd));
886 ssd->listbox->generic.column = 0;
887 ssd->listbox->listbox.height = 7;
889 ssd->loadbutton = ctrl_pushbutton(s, "Load", 'l',
890 HELPCTX(session_saved),
891 sessionsaver_handler, P(ssd));
892 ssd->loadbutton->generic.column = 1;
894 /* We can't offer the Load button mid-session, as it would allow the
895 * user to load and subsequently save settings they can't see. (And
896 * also change otherwise immutable settings underfoot; that probably
897 * shouldn't be a problem, but.) */
898 ssd->loadbutton = NULL;
900 /* "Save" button is permitted mid-session. */
901 ssd->savebutton = ctrl_pushbutton(s, "Save", 'v',
902 HELPCTX(session_saved),
903 sessionsaver_handler, P(ssd));
904 ssd->savebutton->generic.column = 1;
906 ssd->delbutton = ctrl_pushbutton(s, "Delete", 'd',
907 HELPCTX(session_saved),
908 sessionsaver_handler, P(ssd));
909 ssd->delbutton->generic.column = 1;
911 /* Disable the Delete button mid-session too, for UI consistency. */
912 ssd->delbutton = NULL;
914 ctrl_columns(s, 1, 100);
916 s = ctrl_getset(b, "Session", "otheropts", NULL);
917 c = ctrl_radiobuttons(s, "Close window on exit:", 'w', 4,
918 HELPCTX(session_coe),
919 dlg_stdradiobutton_handler,
920 I(offsetof(Config, close_on_exit)),
921 "Always", I(FORCE_ON),
922 "Never", I(FORCE_OFF),
923 "Only on clean exit", I(AUTO), NULL);
926 * The Session/Logging panel.
928 ctrl_settitle(b, "Session/Logging", "Options controlling session logging");
930 s = ctrl_getset(b, "Session/Logging", "main", NULL);
932 * The logging buttons change depending on whether SSH packet
933 * logging can sensibly be available.
937 if ((midsession && protocol == PROT_SSH) ||
938 (!midsession && backends[3].name != NULL))
939 sshlogname = "Log SSH packet data";
941 sshlogname = NULL; /* this will disable the button */
942 ctrl_radiobuttons(s, "Session logging:", NO_SHORTCUT, 1,
943 HELPCTX(logging_main),
944 dlg_stdradiobutton_handler,
945 I(offsetof(Config, logtype)),
946 "Logging turned off completely", 't', I(LGTYP_NONE),
947 "Log printable output only", 'p', I(LGTYP_ASCII),
948 "Log all session output", 'l', I(LGTYP_DEBUG),
949 sshlogname, 's', I(LGTYP_PACKETS),
952 ctrl_filesel(s, "Log file name:", 'f',
953 NULL, TRUE, "Select session log file name",
954 HELPCTX(logging_filename),
955 dlg_stdfilesel_handler, I(offsetof(Config, logfilename)));
956 ctrl_text(s, "(Log file name can contain &Y, &M, &D for date,"
957 " &T for time, and &H for host name)",
958 HELPCTX(logging_filename));
959 ctrl_radiobuttons(s, "What to do if the log file already exists:", 'e', 1,
960 HELPCTX(logging_exists),
961 dlg_stdradiobutton_handler, I(offsetof(Config,logxfovr)),
962 "Always overwrite it", I(LGXF_OVR),
963 "Always append to the end of it", I(LGXF_APN),
964 "Ask the user every time", I(LGXF_ASK), NULL);
965 ctrl_checkbox(s, "Flush log file frequently", 'u',
966 HELPCTX(logging_flush),
967 dlg_stdcheckbox_handler, I(offsetof(Config,logflush)));
969 if ((midsession && protocol == PROT_SSH) ||
970 (!midsession && backends[3].name != NULL)) {
971 s = ctrl_getset(b, "Session/Logging", "ssh",
972 "Options specific to SSH packet logging");
973 ctrl_checkbox(s, "Omit known password fields", 'k',
974 HELPCTX(logging_ssh_omit_password),
975 dlg_stdcheckbox_handler, I(offsetof(Config,logomitpass)));
976 ctrl_checkbox(s, "Omit session data", 'd',
977 HELPCTX(logging_ssh_omit_data),
978 dlg_stdcheckbox_handler, I(offsetof(Config,logomitdata)));
982 * The Terminal panel.
984 ctrl_settitle(b, "Terminal", "Options controlling the terminal emulation");
986 s = ctrl_getset(b, "Terminal", "general", "Set various terminal options");
987 ctrl_checkbox(s, "Auto wrap mode initially on", 'w',
988 HELPCTX(terminal_autowrap),
989 dlg_stdcheckbox_handler, I(offsetof(Config,wrap_mode)));
990 ctrl_checkbox(s, "DEC Origin Mode initially on", 'd',
991 HELPCTX(terminal_decom),
992 dlg_stdcheckbox_handler, I(offsetof(Config,dec_om)));
993 ctrl_checkbox(s, "Implicit CR in every LF", 'r',
994 HELPCTX(terminal_lfhascr),
995 dlg_stdcheckbox_handler, I(offsetof(Config,lfhascr)));
996 ctrl_checkbox(s, "Use background colour to erase screen", 'e',
997 HELPCTX(terminal_bce),
998 dlg_stdcheckbox_handler, I(offsetof(Config,bce)));
999 ctrl_checkbox(s, "Enable blinking text", 'n',
1000 HELPCTX(terminal_blink),
1001 dlg_stdcheckbox_handler, I(offsetof(Config,blinktext)));
1002 ctrl_editbox(s, "Answerback to ^E:", 's', 100,
1003 HELPCTX(terminal_answerback),
1004 dlg_stdeditbox_handler, I(offsetof(Config,answerback)),
1005 I(sizeof(((Config *)0)->answerback)));
1007 s = ctrl_getset(b, "Terminal", "ldisc", "Line discipline options");
1008 ctrl_radiobuttons(s, "Local echo:", 'l', 3,
1009 HELPCTX(terminal_localecho),
1010 dlg_stdradiobutton_handler,I(offsetof(Config,localecho)),
1012 "Force on", I(FORCE_ON),
1013 "Force off", I(FORCE_OFF), NULL);
1014 ctrl_radiobuttons(s, "Local line editing:", 't', 3,
1015 HELPCTX(terminal_localedit),
1016 dlg_stdradiobutton_handler,I(offsetof(Config,localedit)),
1018 "Force on", I(FORCE_ON),
1019 "Force off", I(FORCE_OFF), NULL);
1021 s = ctrl_getset(b, "Terminal", "printing", "Remote-controlled printing");
1022 ctrl_combobox(s, "Printer to send ANSI printer output to:", 'p', 100,
1023 HELPCTX(terminal_printing),
1024 printerbox_handler, P(NULL), P(NULL));
1027 * The Terminal/Keyboard panel.
1029 ctrl_settitle(b, "Terminal/Keyboard",
1030 "Options controlling the effects of keys");
1032 s = ctrl_getset(b, "Terminal/Keyboard", "mappings",
1033 "Change the sequences sent by:");
1034 ctrl_radiobuttons(s, "The Backspace key", 'b', 2,
1035 HELPCTX(keyboard_backspace),
1036 dlg_stdradiobutton_handler,
1037 I(offsetof(Config, bksp_is_delete)),
1038 "Control-H", I(0), "Control-? (127)", I(1), NULL);
1039 ctrl_radiobuttons(s, "The Home and End keys", 'e', 2,
1040 HELPCTX(keyboard_homeend),
1041 dlg_stdradiobutton_handler,
1042 I(offsetof(Config, rxvt_homeend)),
1043 "Standard", I(0), "rxvt", I(1), NULL);
1044 ctrl_radiobuttons(s, "The Function keys and keypad", 'f', 3,
1045 HELPCTX(keyboard_funkeys),
1046 dlg_stdradiobutton_handler,
1047 I(offsetof(Config, funky_type)),
1048 "ESC[n~", I(0), "Linux", I(1), "Xterm R6", I(2),
1049 "VT400", I(3), "VT100+", I(4), "SCO", I(5), NULL);
1051 s = ctrl_getset(b, "Terminal/Keyboard", "appkeypad",
1052 "Application keypad settings:");
1053 ctrl_radiobuttons(s, "Initial state of cursor keys:", 'r', 3,
1054 HELPCTX(keyboard_appcursor),
1055 dlg_stdradiobutton_handler,
1056 I(offsetof(Config, app_cursor)),
1057 "Normal", I(0), "Application", I(1), NULL);
1058 ctrl_radiobuttons(s, "Initial state of numeric keypad:", 'n', 3,
1059 HELPCTX(keyboard_appkeypad),
1060 numeric_keypad_handler, P(NULL),
1061 "Normal", I(0), "Application", I(1), "NetHack", I(2),
1065 * The Terminal/Bell panel.
1067 ctrl_settitle(b, "Terminal/Bell",
1068 "Options controlling the terminal bell");
1070 s = ctrl_getset(b, "Terminal/Bell", "style", "Set the style of bell");
1071 ctrl_radiobuttons(s, "Action to happen when a bell occurs:", 'b', 1,
1072 HELPCTX(bell_style),
1073 dlg_stdradiobutton_handler, I(offsetof(Config, beep)),
1074 "None (bell disabled)", I(BELL_DISABLED),
1075 "Make default system alert sound", I(BELL_DEFAULT),
1076 "Visual bell (flash window)", I(BELL_VISUAL), NULL);
1078 s = ctrl_getset(b, "Terminal/Bell", "overload",
1079 "Control the bell overload behaviour");
1080 ctrl_checkbox(s, "Bell is temporarily disabled when over-used", 'd',
1081 HELPCTX(bell_overload),
1082 dlg_stdcheckbox_handler, I(offsetof(Config,bellovl)));
1083 ctrl_editbox(s, "Over-use means this many bells...", 'm', 20,
1084 HELPCTX(bell_overload),
1085 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_n)), I(-1));
1086 ctrl_editbox(s, "... in this many seconds", 't', 20,
1087 HELPCTX(bell_overload),
1088 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_t)),
1090 ctrl_text(s, "The bell is re-enabled after a few seconds of silence.",
1091 HELPCTX(bell_overload));
1092 ctrl_editbox(s, "Seconds of silence required", 's', 20,
1093 HELPCTX(bell_overload),
1094 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_s)),
1098 * The Terminal/Features panel.
1100 ctrl_settitle(b, "Terminal/Features",
1101 "Enabling and disabling advanced terminal features");
1103 s = ctrl_getset(b, "Terminal/Features", "main", NULL);
1104 ctrl_checkbox(s, "Disable application cursor keys mode", 'u',
1105 HELPCTX(features_application),
1106 dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_c)));
1107 ctrl_checkbox(s, "Disable application keypad mode", 'k',
1108 HELPCTX(features_application),
1109 dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_k)));
1110 ctrl_checkbox(s, "Disable xterm-style mouse reporting", 'x',
1111 HELPCTX(features_mouse),
1112 dlg_stdcheckbox_handler, I(offsetof(Config,no_mouse_rep)));
1113 ctrl_checkbox(s, "Disable remote-controlled terminal resizing", 's',
1114 HELPCTX(features_resize),
1115 dlg_stdcheckbox_handler,
1116 I(offsetof(Config,no_remote_resize)));
1117 ctrl_checkbox(s, "Disable switching to alternate terminal screen", 'w',
1118 HELPCTX(features_altscreen),
1119 dlg_stdcheckbox_handler, I(offsetof(Config,no_alt_screen)));
1120 ctrl_checkbox(s, "Disable remote-controlled window title changing", 't',
1121 HELPCTX(features_retitle),
1122 dlg_stdcheckbox_handler,
1123 I(offsetof(Config,no_remote_wintitle)));
1124 ctrl_checkbox(s, "Disable remote window title querying (SECURITY)",
1125 'q', HELPCTX(features_qtitle), dlg_stdcheckbox_handler,
1126 I(offsetof(Config,no_remote_qtitle)));
1127 ctrl_checkbox(s, "Disable destructive backspace on server sending ^?",'b',
1128 HELPCTX(features_dbackspace),
1129 dlg_stdcheckbox_handler, I(offsetof(Config,no_dbackspace)));
1130 ctrl_checkbox(s, "Disable remote-controlled character set configuration",
1131 'r', HELPCTX(features_charset), dlg_stdcheckbox_handler,
1132 I(offsetof(Config,no_remote_charset)));
1133 ctrl_checkbox(s, "Disable Arabic text shaping",
1134 'l', HELPCTX(features_arabicshaping), dlg_stdcheckbox_handler,
1135 I(offsetof(Config, arabicshaping)));
1136 ctrl_checkbox(s, "Disable bidirectional text display",
1137 'd', HELPCTX(features_bidi), dlg_stdcheckbox_handler,
1138 I(offsetof(Config, bidi)));
1143 str = dupprintf("Options controlling %s's window", appname);
1144 ctrl_settitle(b, "Window", str);
1147 s = ctrl_getset(b, "Window", "size", "Set the size of the window");
1148 ctrl_columns(s, 2, 50, 50);
1149 c = ctrl_editbox(s, "Rows", 'r', 100,
1150 HELPCTX(window_size),
1151 dlg_stdeditbox_handler, I(offsetof(Config,height)),I(-1));
1152 c->generic.column = 0;
1153 c = ctrl_editbox(s, "Columns", 'm', 100,
1154 HELPCTX(window_size),
1155 dlg_stdeditbox_handler, I(offsetof(Config,width)), I(-1));
1156 c->generic.column = 1;
1157 ctrl_columns(s, 1, 100);
1159 s = ctrl_getset(b, "Window", "scrollback",
1160 "Control the scrollback in the window");
1161 ctrl_editbox(s, "Lines of scrollback", 's', 50,
1162 HELPCTX(window_scrollback),
1163 dlg_stdeditbox_handler, I(offsetof(Config,savelines)), I(-1));
1164 ctrl_checkbox(s, "Display scrollbar", 'd',
1165 HELPCTX(window_scrollback),
1166 dlg_stdcheckbox_handler, I(offsetof(Config,scrollbar)));
1167 ctrl_checkbox(s, "Reset scrollback on keypress", 'k',
1168 HELPCTX(window_scrollback),
1169 dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_key)));
1170 ctrl_checkbox(s, "Reset scrollback on display activity", 'p',
1171 HELPCTX(window_scrollback),
1172 dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_disp)));
1173 ctrl_checkbox(s, "Push erased text into scrollback", 'e',
1174 HELPCTX(window_erased),
1175 dlg_stdcheckbox_handler,
1176 I(offsetof(Config,erase_to_scrollback)));
1179 * The Window/Appearance panel.
1181 str = dupprintf("Configure the appearance of %s's window", appname);
1182 ctrl_settitle(b, "Window/Appearance", str);
1185 s = ctrl_getset(b, "Window/Appearance", "cursor",
1186 "Adjust the use of the cursor");
1187 ctrl_radiobuttons(s, "Cursor appearance:", NO_SHORTCUT, 3,
1188 HELPCTX(appearance_cursor),
1189 dlg_stdradiobutton_handler,
1190 I(offsetof(Config, cursor_type)),
1192 "Underline", 'u', I(1),
1193 "Vertical line", 'v', I(2), NULL);
1194 ctrl_checkbox(s, "Cursor blinks", 'b',
1195 HELPCTX(appearance_cursor),
1196 dlg_stdcheckbox_handler, I(offsetof(Config,blink_cur)));
1198 s = ctrl_getset(b, "Window/Appearance", "font",
1200 ctrl_fontsel(s, "Font used in the terminal window", 'n',
1201 HELPCTX(appearance_font),
1202 dlg_stdfontsel_handler, I(offsetof(Config, font)));
1204 s = ctrl_getset(b, "Window/Appearance", "mouse",
1205 "Adjust the use of the mouse pointer");
1206 ctrl_checkbox(s, "Hide mouse pointer when typing in window", 'p',
1207 HELPCTX(appearance_hidemouse),
1208 dlg_stdcheckbox_handler, I(offsetof(Config,hide_mouseptr)));
1210 s = ctrl_getset(b, "Window/Appearance", "border",
1211 "Adjust the window border");
1212 ctrl_editbox(s, "Gap between text and window edge:", NO_SHORTCUT, 20,
1213 HELPCTX(appearance_border),
1214 dlg_stdeditbox_handler,
1215 I(offsetof(Config,window_border)), I(-1));
1218 * The Window/Behaviour panel.
1220 str = dupprintf("Configure the behaviour of %s's window", appname);
1221 ctrl_settitle(b, "Window/Behaviour", str);
1224 s = ctrl_getset(b, "Window/Behaviour", "title",
1225 "Adjust the behaviour of the window title");
1226 ctrl_editbox(s, "Window title:", 't', 100,
1227 HELPCTX(appearance_title),
1228 dlg_stdeditbox_handler, I(offsetof(Config,wintitle)),
1229 I(sizeof(((Config *)0)->wintitle)));
1230 ctrl_checkbox(s, "Separate window and icon titles", 'i',
1231 HELPCTX(appearance_title),
1232 dlg_stdcheckbox_handler,
1233 I(CHECKBOX_INVERT | offsetof(Config,win_name_always)));
1235 s = ctrl_getset(b, "Window/Behaviour", "main", NULL);
1236 ctrl_checkbox(s, "Warn before closing window", 'w',
1237 HELPCTX(behaviour_closewarn),
1238 dlg_stdcheckbox_handler, I(offsetof(Config,warn_on_close)));
1241 * The Window/Translation panel.
1243 ctrl_settitle(b, "Window/Translation",
1244 "Options controlling character set translation");
1246 s = ctrl_getset(b, "Window/Translation", "trans",
1247 "Character set translation on received data");
1248 ctrl_combobox(s, "Received data assumed to be in which character set:",
1249 'r', 100, HELPCTX(translation_codepage),
1250 codepage_handler, P(NULL), P(NULL));
1252 str = dupprintf("Adjust how %s handles line drawing characters", appname);
1253 s = ctrl_getset(b, "Window/Translation", "linedraw", str);
1255 ctrl_radiobuttons(s, "Handling of line drawing characters:", NO_SHORTCUT,1,
1256 HELPCTX(translation_linedraw),
1257 dlg_stdradiobutton_handler,
1258 I(offsetof(Config, vtmode)),
1259 "Use Unicode line drawing code points",'u',I(VT_UNICODE),
1260 "Poor man's line drawing (+, - and |)",'p',I(VT_POORMAN),
1262 ctrl_checkbox(s, "Copy and paste line drawing characters as lqqqk",'d',
1263 HELPCTX(selection_linedraw),
1264 dlg_stdcheckbox_handler, I(offsetof(Config,rawcnp)));
1267 * The Window/Selection panel.
1269 ctrl_settitle(b, "Window/Selection", "Options controlling copy and paste");
1271 s = ctrl_getset(b, "Window/Selection", "mouse",
1272 "Control use of mouse");
1273 ctrl_checkbox(s, "Shift overrides application's use of mouse", 'p',
1274 HELPCTX(selection_shiftdrag),
1275 dlg_stdcheckbox_handler, I(offsetof(Config,mouse_override)));
1276 ctrl_radiobuttons(s,
1277 "Default selection mode (Alt+drag does the other one):",
1279 HELPCTX(selection_rect),
1280 dlg_stdradiobutton_handler,
1281 I(offsetof(Config, rect_select)),
1282 "Normal", 'n', I(0),
1283 "Rectangular block", 'r', I(1), NULL);
1285 s = ctrl_getset(b, "Window/Selection", "charclass",
1286 "Control the select-one-word-at-a-time mode");
1287 ccd = (struct charclass_data *)
1288 ctrl_alloc(b, sizeof(struct charclass_data));
1289 ccd->listbox = ctrl_listbox(s, "Character classes:", 'e',
1290 HELPCTX(selection_charclasses),
1291 charclass_handler, P(ccd));
1292 ccd->listbox->listbox.multisel = 1;
1293 ccd->listbox->listbox.ncols = 4;
1294 ccd->listbox->listbox.percentages = snewn(4, int);
1295 ccd->listbox->listbox.percentages[0] = 15;
1296 ccd->listbox->listbox.percentages[1] = 25;
1297 ccd->listbox->listbox.percentages[2] = 20;
1298 ccd->listbox->listbox.percentages[3] = 40;
1299 ctrl_columns(s, 2, 67, 33);
1300 ccd->editbox = ctrl_editbox(s, "Set to class", 't', 50,
1301 HELPCTX(selection_charclasses),
1302 charclass_handler, P(ccd), P(NULL));
1303 ccd->editbox->generic.column = 0;
1304 ccd->button = ctrl_pushbutton(s, "Set", 's',
1305 HELPCTX(selection_charclasses),
1306 charclass_handler, P(ccd));
1307 ccd->button->generic.column = 1;
1308 ctrl_columns(s, 1, 100);
1311 * The Window/Colours panel.
1313 ctrl_settitle(b, "Window/Colours", "Options controlling use of colours");
1315 s = ctrl_getset(b, "Window/Colours", "general",
1316 "General options for colour usage");
1317 ctrl_checkbox(s, "Allow terminal to specify ANSI colours", 'i',
1318 HELPCTX(colours_ansi),
1319 dlg_stdcheckbox_handler, I(offsetof(Config,ansi_colour)));
1320 ctrl_checkbox(s, "Allow terminal to use xterm 256-colour mode", '2',
1321 HELPCTX(colours_xterm256), dlg_stdcheckbox_handler,
1322 I(offsetof(Config,xterm_256_colour)));
1323 ctrl_checkbox(s, "Bolded text is a different colour", 'b',
1324 HELPCTX(colours_bold),
1325 dlg_stdcheckbox_handler, I(offsetof(Config,bold_colour)));
1327 str = dupprintf("Adjust the precise colours %s displays", appname);
1328 s = ctrl_getset(b, "Window/Colours", "adjust", str);
1330 ctrl_text(s, "Select a colour from the list, and then click the"
1331 " Modify button to change its appearance.",
1332 HELPCTX(colours_config));
1333 ctrl_columns(s, 2, 67, 33);
1334 cd = (struct colour_data *)ctrl_alloc(b, sizeof(struct colour_data));
1335 cd->listbox = ctrl_listbox(s, "Select a colour to adjust:", 'u',
1336 HELPCTX(colours_config), colour_handler, P(cd));
1337 cd->listbox->generic.column = 0;
1338 cd->listbox->listbox.height = 7;
1339 c = ctrl_text(s, "RGB value:", HELPCTX(colours_config));
1340 c->generic.column = 1;
1341 cd->redit = ctrl_editbox(s, "Red", 'r', 50, HELPCTX(colours_config),
1342 colour_handler, P(cd), P(NULL));
1343 cd->redit->generic.column = 1;
1344 cd->gedit = ctrl_editbox(s, "Green", 'n', 50, HELPCTX(colours_config),
1345 colour_handler, P(cd), P(NULL));
1346 cd->gedit->generic.column = 1;
1347 cd->bedit = ctrl_editbox(s, "Blue", 'e', 50, HELPCTX(colours_config),
1348 colour_handler, P(cd), P(NULL));
1349 cd->bedit->generic.column = 1;
1350 cd->button = ctrl_pushbutton(s, "Modify", 'm', HELPCTX(colours_config),
1351 colour_handler, P(cd));
1352 cd->button->generic.column = 1;
1353 ctrl_columns(s, 1, 100);
1356 * The Connection panel. This doesn't show up if we're in a
1357 * non-network utility such as pterm. We tell this by being
1358 * passed a protocol < 0.
1360 if (protocol >= 0) {
1361 ctrl_settitle(b, "Connection", "Options controlling the connection");
1363 s = ctrl_getset(b, "Connection", "keepalive",
1364 "Sending of null packets to keep session active");
1365 ctrl_editbox(s, "Seconds between keepalives (0 to turn off)", 'k', 20,
1366 HELPCTX(connection_keepalive),
1367 dlg_stdeditbox_handler, I(offsetof(Config,ping_interval)),
1371 s = ctrl_getset(b, "Connection", "tcp",
1372 "Low-level TCP connection options");
1373 ctrl_checkbox(s, "Disable Nagle's algorithm (TCP_NODELAY option)",
1374 'n', HELPCTX(connection_nodelay),
1375 dlg_stdcheckbox_handler,
1376 I(offsetof(Config,tcp_nodelay)));
1377 ctrl_checkbox(s, "Enable TCP keepalives (SO_KEEPALIVE option)",
1378 'p', HELPCTX(connection_tcpkeepalive),
1379 dlg_stdcheckbox_handler,
1380 I(offsetof(Config,tcp_keepalives)));
1381 s = ctrl_getset(b, "Connection", "ipversion",
1382 "Internet protocol version");
1383 ctrl_radiobuttons(s, NULL, NO_SHORTCUT,
1389 HELPCTX(connection_ipversion),
1390 dlg_stdradiobutton_handler,
1391 I(offsetof(Config, addressfamily)),
1392 "Auto", NO_SHORTCUT, I(ADDRTYPE_UNSPEC),
1393 "IPv4", NO_SHORTCUT, I(ADDRTYPE_IPV4),
1395 "IPv6", NO_SHORTCUT, I(ADDRTYPE_IPV6),
1401 * A sub-panel Connection/Data, containing options that
1402 * decide on data to send to the server.
1405 ctrl_settitle(b, "Connection/Data", "Data to send to the server");
1407 s = ctrl_getset(b, "Connection/Data", "login",
1409 ctrl_editbox(s, "Auto-login username", 'u', 50,
1410 HELPCTX(connection_username),
1411 dlg_stdeditbox_handler, I(offsetof(Config,username)),
1412 I(sizeof(((Config *)0)->username)));
1414 s = ctrl_getset(b, "Connection/Data", "term",
1415 "Terminal details");
1416 ctrl_editbox(s, "Terminal-type string", 't', 50,
1417 HELPCTX(connection_termtype),
1418 dlg_stdeditbox_handler, I(offsetof(Config,termtype)),
1419 I(sizeof(((Config *)0)->termtype)));
1420 ctrl_editbox(s, "Terminal speeds", 's', 50,
1421 HELPCTX(connection_termspeed),
1422 dlg_stdeditbox_handler, I(offsetof(Config,termspeed)),
1423 I(sizeof(((Config *)0)->termspeed)));
1425 s = ctrl_getset(b, "Connection/Data", "env",
1426 "Environment variables");
1427 ctrl_columns(s, 2, 80, 20);
1428 ed = (struct environ_data *)
1429 ctrl_alloc(b, sizeof(struct environ_data));
1430 ed->varbox = ctrl_editbox(s, "Variable", 'v', 60,
1431 HELPCTX(telnet_environ),
1432 environ_handler, P(ed), P(NULL));
1433 ed->varbox->generic.column = 0;
1434 ed->valbox = ctrl_editbox(s, "Value", 'l', 60,
1435 HELPCTX(telnet_environ),
1436 environ_handler, P(ed), P(NULL));
1437 ed->valbox->generic.column = 0;
1438 ed->addbutton = ctrl_pushbutton(s, "Add", 'd',
1439 HELPCTX(telnet_environ),
1440 environ_handler, P(ed));
1441 ed->addbutton->generic.column = 1;
1442 ed->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1443 HELPCTX(telnet_environ),
1444 environ_handler, P(ed));
1445 ed->rembutton->generic.column = 1;
1446 ctrl_columns(s, 1, 100);
1447 ed->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1448 HELPCTX(telnet_environ),
1449 environ_handler, P(ed));
1450 ed->listbox->listbox.height = 3;
1451 ed->listbox->listbox.ncols = 2;
1452 ed->listbox->listbox.percentages = snewn(2, int);
1453 ed->listbox->listbox.percentages[0] = 30;
1454 ed->listbox->listbox.percentages[1] = 70;
1461 * The Connection/Proxy panel.
1463 ctrl_settitle(b, "Connection/Proxy",
1464 "Options controlling proxy usage");
1466 s = ctrl_getset(b, "Connection/Proxy", "basics", NULL);
1467 ctrl_radiobuttons(s, "Proxy type:", 't', 3,
1468 HELPCTX(proxy_type),
1469 dlg_stdradiobutton_handler,
1470 I(offsetof(Config, proxy_type)),
1471 "None", I(PROXY_NONE),
1472 "SOCKS 4", I(PROXY_SOCKS4),
1473 "SOCKS 5", I(PROXY_SOCKS5),
1474 "HTTP", I(PROXY_HTTP),
1475 "Telnet", I(PROXY_TELNET),
1477 ctrl_columns(s, 2, 80, 20);
1478 c = ctrl_editbox(s, "Proxy hostname", 'y', 100,
1479 HELPCTX(proxy_main),
1480 dlg_stdeditbox_handler,
1481 I(offsetof(Config,proxy_host)),
1482 I(sizeof(((Config *)0)->proxy_host)));
1483 c->generic.column = 0;
1484 c = ctrl_editbox(s, "Port", 'p', 100,
1485 HELPCTX(proxy_main),
1486 dlg_stdeditbox_handler,
1487 I(offsetof(Config,proxy_port)),
1489 c->generic.column = 1;
1490 ctrl_columns(s, 1, 100);
1491 ctrl_editbox(s, "Exclude Hosts/IPs", 'e', 100,
1492 HELPCTX(proxy_exclude),
1493 dlg_stdeditbox_handler,
1494 I(offsetof(Config,proxy_exclude_list)),
1495 I(sizeof(((Config *)0)->proxy_exclude_list)));
1496 ctrl_checkbox(s, "Consider proxying local host connections", 'x',
1497 HELPCTX(proxy_exclude),
1498 dlg_stdcheckbox_handler,
1499 I(offsetof(Config,even_proxy_localhost)));
1500 ctrl_radiobuttons(s, "Do DNS name lookup at proxy end:", 'd', 3,
1502 dlg_stdradiobutton_handler,
1503 I(offsetof(Config, proxy_dns)),
1506 "Yes", I(FORCE_ON), NULL);
1507 ctrl_editbox(s, "Username", 'u', 60,
1508 HELPCTX(proxy_auth),
1509 dlg_stdeditbox_handler,
1510 I(offsetof(Config,proxy_username)),
1511 I(sizeof(((Config *)0)->proxy_username)));
1512 c = ctrl_editbox(s, "Password", 'w', 60,
1513 HELPCTX(proxy_auth),
1514 dlg_stdeditbox_handler,
1515 I(offsetof(Config,proxy_password)),
1516 I(sizeof(((Config *)0)->proxy_password)));
1517 c->editbox.password = 1;
1518 ctrl_editbox(s, "Telnet command", 'm', 100,
1519 HELPCTX(proxy_command),
1520 dlg_stdeditbox_handler,
1521 I(offsetof(Config,proxy_telnet_command)),
1522 I(sizeof(((Config *)0)->proxy_telnet_command)));
1526 * The Telnet panel exists in the base config box, and in a
1527 * mid-session reconfig box _if_ we're using Telnet.
1529 if (!midsession || protocol == PROT_TELNET) {
1531 * The Connection/Telnet panel.
1533 ctrl_settitle(b, "Connection/Telnet",
1534 "Options controlling Telnet connections");
1536 s = ctrl_getset(b, "Connection/Telnet", "protocol",
1537 "Telnet protocol adjustments");
1540 ctrl_radiobuttons(s, "Handling of OLD_ENVIRON ambiguity:",
1542 HELPCTX(telnet_oldenviron),
1543 dlg_stdradiobutton_handler,
1544 I(offsetof(Config, rfc_environ)),
1545 "BSD (commonplace)", 'b', I(0),
1546 "RFC 1408 (unusual)", 'f', I(1), NULL);
1547 ctrl_radiobuttons(s, "Telnet negotiation mode:", 't', 2,
1548 HELPCTX(telnet_passive),
1549 dlg_stdradiobutton_handler,
1550 I(offsetof(Config, passive_telnet)),
1551 "Passive", I(1), "Active", I(0), NULL);
1553 ctrl_checkbox(s, "Keyboard sends Telnet special commands", 'k',
1554 HELPCTX(telnet_specialkeys),
1555 dlg_stdcheckbox_handler,
1556 I(offsetof(Config,telnet_keyboard)));
1557 ctrl_checkbox(s, "Return key sends Telnet New Line instead of ^M",
1558 'm', HELPCTX(telnet_newline),
1559 dlg_stdcheckbox_handler,
1560 I(offsetof(Config,telnet_newline)));
1566 * The Connection/Rlogin panel.
1568 ctrl_settitle(b, "Connection/Rlogin",
1569 "Options controlling Rlogin connections");
1571 s = ctrl_getset(b, "Connection/Rlogin", "data",
1572 "Data to send to the server");
1573 ctrl_editbox(s, "Local username:", 'l', 50,
1574 HELPCTX(rlogin_localuser),
1575 dlg_stdeditbox_handler, I(offsetof(Config,localusername)),
1576 I(sizeof(((Config *)0)->localusername)));
1581 * All the SSH stuff is omitted in PuTTYtel, or in a reconfig
1582 * when we're not doing SSH.
1585 if (backends[3].name != NULL && (!midsession || protocol == PROT_SSH)) {
1588 * The Connection/SSH panel.
1590 ctrl_settitle(b, "Connection/SSH",
1591 "Options controlling SSH connections");
1593 if (midsession && protcfginfo == 1) {
1594 s = ctrl_getset(b, "Connection/SSH", "disclaimer", NULL);
1595 ctrl_text(s, "Nothing on this panel may be reconfigured in mid-"
1596 "session; it is only here so that sub-panels of it can "
1597 "exist without looking strange.", HELPCTX(no_help));
1602 s = ctrl_getset(b, "Connection/SSH", "data",
1603 "Data to send to the server");
1604 ctrl_editbox(s, "Remote command:", 'r', 100,
1605 HELPCTX(ssh_command),
1606 dlg_stdeditbox_handler, I(offsetof(Config,remote_cmd)),
1607 I(sizeof(((Config *)0)->remote_cmd)));
1609 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1610 ctrl_checkbox(s, "Don't allocate a pseudo-terminal", 'p',
1612 dlg_stdcheckbox_handler,
1613 I(offsetof(Config,nopty)));
1614 ctrl_checkbox(s, "Don't start a shell or command at all", 'n',
1615 HELPCTX(ssh_noshell),
1616 dlg_stdcheckbox_handler,
1617 I(offsetof(Config,ssh_no_shell)));
1620 if (!midsession || protcfginfo != 1) {
1621 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1623 ctrl_checkbox(s, "Enable compression", 'e',
1624 HELPCTX(ssh_compress),
1625 dlg_stdcheckbox_handler,
1626 I(offsetof(Config,compression)));
1630 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1632 ctrl_radiobuttons(s, "Preferred SSH protocol version:", NO_SHORTCUT, 4,
1633 HELPCTX(ssh_protocol),
1634 dlg_stdradiobutton_handler,
1635 I(offsetof(Config, sshprot)),
1636 "1 only", 'l', I(0),
1639 "2 only", 'y', I(3), NULL);
1642 if (!midsession || protcfginfo != 1) {
1643 s = ctrl_getset(b, "Connection/SSH", "encryption", "Encryption options");
1644 c = ctrl_draglist(s, "Encryption cipher selection policy:", 's',
1645 HELPCTX(ssh_ciphers),
1646 cipherlist_handler, P(NULL));
1647 c->listbox.height = 6;
1649 ctrl_checkbox(s, "Enable legacy use of single-DES in SSH 2", 'i',
1650 HELPCTX(ssh_ciphers),
1651 dlg_stdcheckbox_handler,
1652 I(offsetof(Config,ssh2_des_cbc)));
1656 * The Connection/SSH/Kex panel. (Owing to repeat key
1657 * exchange, this is all meaningful in mid-session _if_
1658 * we're using SSH2 or haven't decided yet.)
1660 if (protcfginfo != 1) {
1661 ctrl_settitle(b, "Connection/SSH/Kex",
1662 "Options controlling SSH key exchange");
1664 s = ctrl_getset(b, "Connection/SSH/Kex", "main",
1665 "Key exchange algorithm options");
1666 c = ctrl_draglist(s, "Algorithm selection policy:", 's',
1667 HELPCTX(ssh_kexlist),
1668 kexlist_handler, P(NULL));
1669 c->listbox.height = 5;
1671 s = ctrl_getset(b, "Connection/SSH/Kex", "repeat",
1672 "Options controlling key re-exchange");
1674 ctrl_editbox(s, "Max minutes before rekey (0 for no limit)", 't', 20,
1675 HELPCTX(ssh_kex_repeat),
1676 dlg_stdeditbox_handler,
1677 I(offsetof(Config,ssh_rekey_time)),
1679 ctrl_editbox(s, "Max data before rekey (0 for no limit)", 'x', 20,
1680 HELPCTX(ssh_kex_repeat),
1681 dlg_stdeditbox_handler,
1682 I(offsetof(Config,ssh_rekey_data)),
1684 ctrl_text(s, "(Use 1M for 1 megabyte, 1G for 1 gigabyte etc)",
1685 HELPCTX(ssh_kex_repeat));
1691 * The Connection/SSH/Auth panel.
1693 ctrl_settitle(b, "Connection/SSH/Auth",
1694 "Options controlling SSH authentication");
1696 s = ctrl_getset(b, "Connection/SSH/Auth", "methods",
1697 "Authentication methods");
1698 ctrl_checkbox(s, "Attempt TIS or CryptoCard auth (SSH1)", 'm',
1699 HELPCTX(ssh_auth_tis),
1700 dlg_stdcheckbox_handler,
1701 I(offsetof(Config,try_tis_auth)));
1702 ctrl_checkbox(s, "Attempt \"keyboard-interactive\" auth (SSH2)",
1703 'i', HELPCTX(ssh_auth_ki),
1704 dlg_stdcheckbox_handler,
1705 I(offsetof(Config,try_ki_auth)));
1707 s = ctrl_getset(b, "Connection/SSH/Auth", "params",
1708 "Authentication parameters");
1709 ctrl_checkbox(s, "Allow agent forwarding", 'f',
1710 HELPCTX(ssh_auth_agentfwd),
1711 dlg_stdcheckbox_handler, I(offsetof(Config,agentfwd)));
1712 ctrl_checkbox(s, "Allow attempted changes of username in SSH2", 'u',
1713 HELPCTX(ssh_auth_changeuser),
1714 dlg_stdcheckbox_handler,
1715 I(offsetof(Config,change_username)));
1716 ctrl_filesel(s, "Private key file for authentication:", 'k',
1717 FILTER_KEY_FILES, FALSE, "Select private key file",
1718 HELPCTX(ssh_auth_privkey),
1719 dlg_stdfilesel_handler, I(offsetof(Config, keyfile)));
1724 * The Connection/SSH/X11 panel.
1726 ctrl_settitle(b, "Connection/SSH/X11",
1727 "Options controlling SSH X11 forwarding");
1729 s = ctrl_getset(b, "Connection/SSH/X11", "x11", "X11 forwarding");
1730 ctrl_checkbox(s, "Enable X11 forwarding", 'e',
1731 HELPCTX(ssh_tunnels_x11),
1732 dlg_stdcheckbox_handler,I(offsetof(Config,x11_forward)));
1733 ctrl_editbox(s, "X display location", 'x', 50,
1734 HELPCTX(ssh_tunnels_x11),
1735 dlg_stdeditbox_handler, I(offsetof(Config,x11_display)),
1736 I(sizeof(((Config *)0)->x11_display)));
1737 ctrl_radiobuttons(s, "Remote X11 authentication protocol", 'u', 2,
1738 HELPCTX(ssh_tunnels_x11auth),
1739 dlg_stdradiobutton_handler,
1740 I(offsetof(Config, x11_auth)),
1741 "MIT-Magic-Cookie-1", I(X11_MIT),
1742 "XDM-Authorization-1", I(X11_XDM), NULL);
1746 * The Tunnels panel _is_ still available in mid-session.
1748 ctrl_settitle(b, "Connection/SSH/Tunnels",
1749 "Options controlling SSH port forwarding");
1751 s = ctrl_getset(b, "Connection/SSH/Tunnels", "portfwd",
1753 ctrl_checkbox(s, "Local ports accept connections from other hosts",'t',
1754 HELPCTX(ssh_tunnels_portfwd_localhost),
1755 dlg_stdcheckbox_handler,
1756 I(offsetof(Config,lport_acceptall)));
1757 ctrl_checkbox(s, "Remote ports do the same (SSH v2 only)", 'p',
1758 HELPCTX(ssh_tunnels_portfwd_localhost),
1759 dlg_stdcheckbox_handler,
1760 I(offsetof(Config,rport_acceptall)));
1762 ctrl_columns(s, 3, 55, 20, 25);
1763 c = ctrl_text(s, "Forwarded ports:", HELPCTX(ssh_tunnels_portfwd));
1764 c->generic.column = COLUMN_FIELD(0,2);
1765 /* You want to select from the list, _then_ hit Remove. So tab order
1766 * should be that way round. */
1767 pfd = (struct portfwd_data *)ctrl_alloc(b,sizeof(struct portfwd_data));
1768 pfd->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1769 HELPCTX(ssh_tunnels_portfwd),
1770 portfwd_handler, P(pfd));
1771 pfd->rembutton->generic.column = 2;
1772 pfd->rembutton->generic.tabdelay = 1;
1773 pfd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1774 HELPCTX(ssh_tunnels_portfwd),
1775 portfwd_handler, P(pfd));
1776 pfd->listbox->listbox.height = 3;
1777 pfd->listbox->listbox.ncols = 2;
1778 pfd->listbox->listbox.percentages = snewn(2, int);
1779 pfd->listbox->listbox.percentages[0] = 20;
1780 pfd->listbox->listbox.percentages[1] = 80;
1781 ctrl_tabdelay(s, pfd->rembutton);
1782 ctrl_text(s, "Add new forwarded port:", HELPCTX(ssh_tunnels_portfwd));
1783 /* You want to enter source, destination and type, _then_ hit Add.
1784 * Again, we adjust the tab order to reflect this. */
1785 pfd->addbutton = ctrl_pushbutton(s, "Add", 'd',
1786 HELPCTX(ssh_tunnels_portfwd),
1787 portfwd_handler, P(pfd));
1788 pfd->addbutton->generic.column = 2;
1789 pfd->addbutton->generic.tabdelay = 1;
1790 pfd->sourcebox = ctrl_editbox(s, "Source port", 's', 40,
1791 HELPCTX(ssh_tunnels_portfwd),
1792 portfwd_handler, P(pfd), P(NULL));
1793 pfd->sourcebox->generic.column = 0;
1794 pfd->destbox = ctrl_editbox(s, "Destination", 'i', 67,
1795 HELPCTX(ssh_tunnels_portfwd),
1796 portfwd_handler, P(pfd), P(NULL));
1797 pfd->direction = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
1798 HELPCTX(ssh_tunnels_portfwd),
1799 portfwd_handler, P(pfd),
1800 "Local", 'l', P(NULL),
1801 "Remote", 'm', P(NULL),
1802 "Dynamic", 'y', P(NULL),
1804 pfd->addressfamily =
1805 ctrl_radiobuttons(s, NULL, NO_SHORTCUT,
1811 HELPCTX(ssh_tunnels_portfwd_ipversion),
1812 portfwd_handler, P(pfd),
1813 "Auto", NO_SHORTCUT, I(ADDRTYPE_UNSPEC),
1814 "IPv4", NO_SHORTCUT, I(ADDRTYPE_IPV4),
1816 "IPv6", NO_SHORTCUT, I(ADDRTYPE_IPV6),
1819 ctrl_tabdelay(s, pfd->addbutton);
1820 ctrl_columns(s, 1, 100);
1824 * The Connection/SSH/Bugs panel.
1826 ctrl_settitle(b, "Connection/SSH/Bugs",
1827 "Workarounds for SSH server bugs");
1829 s = ctrl_getset(b, "Connection/SSH/Bugs", "main",
1830 "Detection of known bugs in SSH servers");
1831 ctrl_droplist(s, "Chokes on SSH1 ignore messages", 'i', 20,
1832 HELPCTX(ssh_bugs_ignore1),
1833 sshbug_handler, I(offsetof(Config,sshbug_ignore1)));
1834 ctrl_droplist(s, "Refuses all SSH1 password camouflage", 's', 20,
1835 HELPCTX(ssh_bugs_plainpw1),
1836 sshbug_handler, I(offsetof(Config,sshbug_plainpw1)));
1837 ctrl_droplist(s, "Chokes on SSH1 RSA authentication", 'r', 20,
1838 HELPCTX(ssh_bugs_rsa1),
1839 sshbug_handler, I(offsetof(Config,sshbug_rsa1)));
1840 ctrl_droplist(s, "Miscomputes SSH2 HMAC keys", 'm', 20,
1841 HELPCTX(ssh_bugs_hmac2),
1842 sshbug_handler, I(offsetof(Config,sshbug_hmac2)));
1843 ctrl_droplist(s, "Miscomputes SSH2 encryption keys", 'e', 20,
1844 HELPCTX(ssh_bugs_derivekey2),
1845 sshbug_handler, I(offsetof(Config,sshbug_derivekey2)));
1846 ctrl_droplist(s, "Requires padding on SSH2 RSA signatures", 'p', 20,
1847 HELPCTX(ssh_bugs_rsapad2),
1848 sshbug_handler, I(offsetof(Config,sshbug_rsapad2)));
1849 ctrl_droplist(s, "Misuses the session ID in PK auth", 'n', 20,
1850 HELPCTX(ssh_bugs_pksessid2),
1851 sshbug_handler, I(offsetof(Config,sshbug_pksessid2)));