2 * config.c - the platform-independent parts of the PuTTY
13 #define PRINTER_DISABLED_STRING "None (printing disabled)"
15 static void protocolbuttons_handler(union control *ctrl, void *dlg,
16 void *data, int event)
19 Config *cfg = (Config *)data;
21 * This function works just like the standard radio-button
22 * handler, except that it also has to change the setting of
23 * the port box. We expect the context parameter to point at
24 * the `union control' structure for the port box.
26 if (event == EVENT_REFRESH) {
27 for (button = 0; button < ctrl->radio.nbuttons; button++)
28 if (cfg->protocol == ctrl->radio.buttondata[button].i)
30 /* We expected that `break' to happen, in all circumstances. */
31 assert(button < ctrl->radio.nbuttons);
32 dlg_radiobutton_set(ctrl, dlg, button);
33 } else if (event == EVENT_VALCHANGE) {
34 int oldproto = cfg->protocol;
35 button = dlg_radiobutton_get(ctrl, dlg);
36 assert(button >= 0 && button < ctrl->radio.nbuttons);
37 cfg->protocol = ctrl->radio.buttondata[button].i;
38 if (oldproto != cfg->protocol) {
40 switch (cfg->protocol) {
41 case PROT_SSH: defport = 22; break;
42 case PROT_TELNET: defport = 23; break;
43 case PROT_RLOGIN: defport = 513; break;
45 if (defport > 0 && cfg->port != defport) {
47 dlg_refresh((union control *)ctrl->radio.context.p, dlg);
53 static void loggingbuttons_handler(union control *ctrl, void *dlg,
54 void *data, int event)
57 Config *cfg = (Config *)data;
58 /* This function works just like the standard radio-button handler,
59 * but it has to fall back to "no logging" in situations where the
60 * configured logging type isn't applicable.
62 if (event == EVENT_REFRESH) {
63 for (button = 0; button < ctrl->radio.nbuttons; button++)
64 if (cfg->logtype == ctrl->radio.buttondata[button].i)
67 /* We fell off the end, so we lack the configured logging type */
68 if (button == ctrl->radio.nbuttons) {
70 cfg->logtype=LGTYP_NONE;
72 dlg_radiobutton_set(ctrl, dlg, button);
73 } else if (event == EVENT_VALCHANGE) {
74 button = dlg_radiobutton_get(ctrl, dlg);
75 assert(button >= 0 && button < ctrl->radio.nbuttons);
76 cfg->logtype = ctrl->radio.buttondata[button].i;
80 static void numeric_keypad_handler(union control *ctrl, void *dlg,
81 void *data, int event)
84 Config *cfg = (Config *)data;
86 * This function works much like the standard radio button
87 * handler, but it has to handle two fields in Config.
89 if (event == EVENT_REFRESH) {
90 if (cfg->nethack_keypad)
92 else if (cfg->app_keypad)
96 assert(button < ctrl->radio.nbuttons);
97 dlg_radiobutton_set(ctrl, dlg, button);
98 } else if (event == EVENT_VALCHANGE) {
99 button = dlg_radiobutton_get(ctrl, dlg);
100 assert(button >= 0 && button < ctrl->radio.nbuttons);
102 cfg->app_keypad = FALSE;
103 cfg->nethack_keypad = TRUE;
105 cfg->app_keypad = (button != 0);
106 cfg->nethack_keypad = FALSE;
111 static void cipherlist_handler(union control *ctrl, void *dlg,
112 void *data, int event)
114 Config *cfg = (Config *)data;
115 if (event == EVENT_REFRESH) {
118 static const struct { char *s; int c; } ciphers[] = {
119 { "3DES", CIPHER_3DES },
120 { "Blowfish", CIPHER_BLOWFISH },
121 { "DES", CIPHER_DES },
122 { "AES (SSH-2 only)", CIPHER_AES },
123 { "-- warn below here --", CIPHER_WARN }
126 /* Set up the "selected ciphers" box. */
127 /* (cipherlist assumed to contain all ciphers) */
128 dlg_update_start(ctrl, dlg);
129 dlg_listbox_clear(ctrl, dlg);
130 for (i = 0; i < CIPHER_MAX; i++) {
131 int c = cfg->ssh_cipherlist[i];
134 for (j = 0; j < (sizeof ciphers) / (sizeof ciphers[0]); j++) {
135 if (ciphers[j].c == c) {
140 dlg_listbox_addwithid(ctrl, dlg, cstr, c);
142 dlg_update_done(ctrl, dlg);
144 } else if (event == EVENT_VALCHANGE) {
147 /* Update array to match the list box. */
148 for (i=0; i < CIPHER_MAX; i++)
149 cfg->ssh_cipherlist[i] = dlg_listbox_getid(ctrl, dlg, i);
154 static void kexlist_handler(union control *ctrl, void *dlg,
155 void *data, int event)
157 Config *cfg = (Config *)data;
158 if (event == EVENT_REFRESH) {
161 static const struct { char *s; int k; } kexes[] = {
162 { "Diffie-Hellman group 1", KEX_DHGROUP1 },
163 { "Diffie-Hellman group 14", KEX_DHGROUP14 },
164 { "Diffie-Hellman group exchange", KEX_DHGEX },
165 { "-- warn below here --", KEX_WARN }
168 /* Set up the "kex preference" box. */
169 /* (kexlist assumed to contain all algorithms) */
170 dlg_update_start(ctrl, dlg);
171 dlg_listbox_clear(ctrl, dlg);
172 for (i = 0; i < KEX_MAX; i++) {
173 int k = cfg->ssh_kexlist[i];
176 for (j = 0; j < (sizeof kexes) / (sizeof kexes[0]); j++) {
177 if (kexes[j].k == k) {
182 dlg_listbox_addwithid(ctrl, dlg, kstr, k);
184 dlg_update_done(ctrl, dlg);
186 } else if (event == EVENT_VALCHANGE) {
189 /* Update array to match the list box. */
190 for (i=0; i < KEX_MAX; i++)
191 cfg->ssh_kexlist[i] = dlg_listbox_getid(ctrl, dlg, i);
196 static void printerbox_handler(union control *ctrl, void *dlg,
197 void *data, int event)
199 Config *cfg = (Config *)data;
200 if (event == EVENT_REFRESH) {
204 dlg_update_start(ctrl, dlg);
206 * Some backends may wish to disable the drop-down list on
207 * this edit box. Be prepared for this.
209 if (ctrl->editbox.has_list) {
210 dlg_listbox_clear(ctrl, dlg);
211 dlg_listbox_add(ctrl, dlg, PRINTER_DISABLED_STRING);
212 pe = printer_start_enum(&nprinters);
213 for (i = 0; i < nprinters; i++)
214 dlg_listbox_add(ctrl, dlg, printer_get_name(pe, i));
215 printer_finish_enum(pe);
217 dlg_editbox_set(ctrl, dlg,
218 (*cfg->printer ? cfg->printer :
219 PRINTER_DISABLED_STRING));
220 dlg_update_done(ctrl, dlg);
221 } else if (event == EVENT_VALCHANGE) {
222 dlg_editbox_get(ctrl, dlg, cfg->printer, sizeof(cfg->printer));
223 if (!strcmp(cfg->printer, PRINTER_DISABLED_STRING))
224 *cfg->printer = '\0';
228 static void codepage_handler(union control *ctrl, void *dlg,
229 void *data, int event)
231 Config *cfg = (Config *)data;
232 if (event == EVENT_REFRESH) {
235 dlg_update_start(ctrl, dlg);
236 strcpy(cfg->line_codepage,
237 cp_name(decode_codepage(cfg->line_codepage)));
238 dlg_listbox_clear(ctrl, dlg);
239 for (i = 0; (cp = cp_enumerate(i)) != NULL; i++)
240 dlg_listbox_add(ctrl, dlg, cp);
241 dlg_editbox_set(ctrl, dlg, cfg->line_codepage);
242 dlg_update_done(ctrl, dlg);
243 } else if (event == EVENT_VALCHANGE) {
244 dlg_editbox_get(ctrl, dlg, cfg->line_codepage,
245 sizeof(cfg->line_codepage));
246 strcpy(cfg->line_codepage,
247 cp_name(decode_codepage(cfg->line_codepage)));
251 static void sshbug_handler(union control *ctrl, void *dlg,
252 void *data, int event)
254 if (event == EVENT_REFRESH) {
255 dlg_update_start(ctrl, dlg);
256 dlg_listbox_clear(ctrl, dlg);
257 dlg_listbox_addwithid(ctrl, dlg, "Auto", AUTO);
258 dlg_listbox_addwithid(ctrl, dlg, "Off", FORCE_OFF);
259 dlg_listbox_addwithid(ctrl, dlg, "On", FORCE_ON);
260 switch (*(int *)ATOFFSET(data, ctrl->listbox.context.i)) {
261 case AUTO: dlg_listbox_select(ctrl, dlg, 0); break;
262 case FORCE_OFF: dlg_listbox_select(ctrl, dlg, 1); break;
263 case FORCE_ON: dlg_listbox_select(ctrl, dlg, 2); break;
265 dlg_update_done(ctrl, dlg);
266 } else if (event == EVENT_SELCHANGE) {
267 int i = dlg_listbox_index(ctrl, dlg);
271 i = dlg_listbox_getid(ctrl, dlg, i);
272 *(int *)ATOFFSET(data, ctrl->listbox.context.i) = i;
276 #define SAVEDSESSION_LEN 2048
278 struct sessionsaver_data {
279 union control *editbox, *listbox, *loadbutton, *savebutton, *delbutton;
280 union control *okbutton, *cancelbutton;
281 struct sesslist *sesslist;
286 * Helper function to load the session selected in the list box, if
287 * any, as this is done in more than one place below. Returns 0 for
290 static int load_selected_session(struct sessionsaver_data *ssd,
292 void *dlg, Config *cfg)
294 int i = dlg_listbox_index(ssd->listbox, dlg);
300 isdef = !strcmp(ssd->sesslist->sessions[i], "Default Settings");
301 load_settings(ssd->sesslist->sessions[i], !isdef, cfg);
303 strncpy(savedsession, ssd->sesslist->sessions[i],
305 savedsession[SAVEDSESSION_LEN-1] = '\0';
307 savedsession[0] = '\0';
309 dlg_refresh(NULL, dlg);
310 /* Restore the selection, which might have been clobbered by
311 * changing the value of the edit box. */
312 dlg_listbox_select(ssd->listbox, dlg, i);
316 static void sessionsaver_handler(union control *ctrl, void *dlg,
317 void *data, int event)
319 Config *cfg = (Config *)data;
320 struct sessionsaver_data *ssd =
321 (struct sessionsaver_data *)ctrl->generic.context.p;
325 * The first time we're called in a new dialog, we must
326 * allocate space to store the current contents of the saved
327 * session edit box (since it must persist even when we switch
328 * panels, but is not part of the Config).
332 } else if (!dlg_get_privdata(ssd->editbox, dlg)) {
333 savedsession = (char *)
334 dlg_alloc_privdata(ssd->editbox, dlg, SAVEDSESSION_LEN);
335 savedsession[0] = '\0';
337 savedsession = dlg_get_privdata(ssd->editbox, dlg);
340 if (event == EVENT_REFRESH) {
341 if (ctrl == ssd->editbox) {
342 dlg_editbox_set(ctrl, dlg, savedsession);
343 } else if (ctrl == ssd->listbox) {
345 dlg_update_start(ctrl, dlg);
346 dlg_listbox_clear(ctrl, dlg);
347 for (i = 0; i < ssd->sesslist->nsessions; i++)
348 dlg_listbox_add(ctrl, dlg, ssd->sesslist->sessions[i]);
349 dlg_update_done(ctrl, dlg);
351 } else if (event == EVENT_VALCHANGE) {
352 if (ctrl == ssd->editbox) {
353 dlg_editbox_get(ctrl, dlg, savedsession,
356 } else if (event == EVENT_ACTION) {
357 if (!ssd->midsession &&
358 (ctrl == ssd->listbox ||
359 (ssd->loadbutton && ctrl == ssd->loadbutton))) {
361 * The user has double-clicked a session, or hit Load.
362 * We must load the selected session, and then
363 * terminate the configuration dialog _if_ there was a
364 * double-click on the list box _and_ that session
365 * contains a hostname.
367 if (load_selected_session(ssd, savedsession, dlg, cfg) &&
368 (ctrl == ssd->listbox && cfg->host[0])) {
369 dlg_end(dlg, 1); /* it's all over, and succeeded */
371 } else if (ctrl == ssd->savebutton) {
372 int isdef = !strcmp(savedsession, "Default Settings");
373 if (!savedsession[0]) {
374 int i = dlg_listbox_index(ssd->listbox, dlg);
379 isdef = !strcmp(ssd->sesslist->sessions[i], "Default Settings");
381 strncpy(savedsession, ssd->sesslist->sessions[i],
383 savedsession[SAVEDSESSION_LEN-1] = '\0';
385 savedsession[0] = '\0';
389 char *errmsg = save_settings(savedsession, !isdef, cfg);
391 dlg_error_msg(dlg, errmsg);
395 get_sesslist(ssd->sesslist, FALSE);
396 get_sesslist(ssd->sesslist, TRUE);
397 dlg_refresh(ssd->editbox, dlg);
398 dlg_refresh(ssd->listbox, dlg);
399 } else if (!ssd->midsession &&
400 ssd->delbutton && ctrl == ssd->delbutton) {
401 int i = dlg_listbox_index(ssd->listbox, dlg);
405 del_settings(ssd->sesslist->sessions[i]);
406 get_sesslist(ssd->sesslist, FALSE);
407 get_sesslist(ssd->sesslist, TRUE);
408 dlg_refresh(ssd->listbox, dlg);
410 } else if (ctrl == ssd->okbutton) {
411 if (ssd->midsession) {
412 /* In a mid-session Change Settings, Apply is always OK. */
417 * Annoying special case. If the `Open' button is
418 * pressed while no host name is currently set, _and_
419 * the session list previously had the focus, _and_
420 * there was a session selected in that which had a
421 * valid host name in it, then load it and go.
423 if (dlg_last_focused(ctrl, dlg) == ssd->listbox && !*cfg->host) {
425 if (!load_selected_session(ssd, savedsession, dlg, &cfg2)) {
429 /* If at this point we have a valid session, go! */
431 *cfg = cfg2; /* structure copy */
432 cfg->remote_cmd_ptr = NULL;
440 * Otherwise, do the normal thing: if we have a valid
441 * session, get going.
447 } else if (ctrl == ssd->cancelbutton) {
453 struct charclass_data {
454 union control *listbox, *editbox, *button;
457 static void charclass_handler(union control *ctrl, void *dlg,
458 void *data, int event)
460 Config *cfg = (Config *)data;
461 struct charclass_data *ccd =
462 (struct charclass_data *)ctrl->generic.context.p;
464 if (event == EVENT_REFRESH) {
465 if (ctrl == ccd->listbox) {
467 dlg_update_start(ctrl, dlg);
468 dlg_listbox_clear(ctrl, dlg);
469 for (i = 0; i < 128; i++) {
471 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
472 (i >= 0x21 && i != 0x7F) ? i : ' ', cfg->wordness[i]);
473 dlg_listbox_add(ctrl, dlg, str);
475 dlg_update_done(ctrl, dlg);
477 } else if (event == EVENT_ACTION) {
478 if (ctrl == ccd->button) {
481 dlg_editbox_get(ccd->editbox, dlg, str, sizeof(str));
483 for (i = 0; i < 128; i++) {
484 if (dlg_listbox_issel(ccd->listbox, dlg, i))
485 cfg->wordness[i] = n;
487 dlg_refresh(ccd->listbox, dlg);
493 union control *listbox, *redit, *gedit, *bedit, *button;
496 static const char *const colours[] = {
497 "Default Foreground", "Default Bold Foreground",
498 "Default Background", "Default Bold Background",
499 "Cursor Text", "Cursor Colour",
500 "ANSI Black", "ANSI Black Bold",
501 "ANSI Red", "ANSI Red Bold",
502 "ANSI Green", "ANSI Green Bold",
503 "ANSI Yellow", "ANSI Yellow Bold",
504 "ANSI Blue", "ANSI Blue Bold",
505 "ANSI Magenta", "ANSI Magenta Bold",
506 "ANSI Cyan", "ANSI Cyan Bold",
507 "ANSI White", "ANSI White Bold"
510 static void colour_handler(union control *ctrl, void *dlg,
511 void *data, int event)
513 Config *cfg = (Config *)data;
514 struct colour_data *cd =
515 (struct colour_data *)ctrl->generic.context.p;
516 int update = FALSE, r, g, b;
518 if (event == EVENT_REFRESH) {
519 if (ctrl == cd->listbox) {
521 dlg_update_start(ctrl, dlg);
522 dlg_listbox_clear(ctrl, dlg);
523 for (i = 0; i < lenof(colours); i++)
524 dlg_listbox_add(ctrl, dlg, colours[i]);
525 dlg_update_done(ctrl, dlg);
526 dlg_editbox_set(cd->redit, dlg, "");
527 dlg_editbox_set(cd->gedit, dlg, "");
528 dlg_editbox_set(cd->bedit, dlg, "");
530 } else if (event == EVENT_SELCHANGE) {
531 if (ctrl == cd->listbox) {
532 /* The user has selected a colour. Update the RGB text. */
533 int i = dlg_listbox_index(ctrl, dlg);
538 r = cfg->colours[i][0];
539 g = cfg->colours[i][1];
540 b = cfg->colours[i][2];
543 } else if (event == EVENT_VALCHANGE) {
544 if (ctrl == cd->redit || ctrl == cd->gedit || ctrl == cd->bedit) {
545 /* The user has changed the colour using the edit boxes. */
549 dlg_editbox_get(ctrl, dlg, buf, lenof(buf));
550 cval = atoi(buf) & 255;
552 i = dlg_listbox_index(cd->listbox, dlg);
554 if (ctrl == cd->redit)
555 cfg->colours[i][0] = cval;
556 else if (ctrl == cd->gedit)
557 cfg->colours[i][1] = cval;
558 else if (ctrl == cd->bedit)
559 cfg->colours[i][2] = cval;
562 } else if (event == EVENT_ACTION) {
563 if (ctrl == cd->button) {
564 int i = dlg_listbox_index(cd->listbox, dlg);
570 * Start a colour selector, which will send us an
571 * EVENT_CALLBACK when it's finished and allow us to
572 * pick up the results.
574 dlg_coloursel_start(ctrl, dlg,
579 } else if (event == EVENT_CALLBACK) {
580 if (ctrl == cd->button) {
581 int i = dlg_listbox_index(cd->listbox, dlg);
583 * Collect the results of the colour selector. Will
584 * return nonzero on success, or zero if the colour
585 * selector did nothing (user hit Cancel, for example).
587 if (dlg_coloursel_results(ctrl, dlg, &r, &g, &b)) {
588 cfg->colours[i][0] = r;
589 cfg->colours[i][1] = g;
590 cfg->colours[i][2] = b;
598 sprintf(buf, "%d", r); dlg_editbox_set(cd->redit, dlg, buf);
599 sprintf(buf, "%d", g); dlg_editbox_set(cd->gedit, dlg, buf);
600 sprintf(buf, "%d", b); dlg_editbox_set(cd->bedit, dlg, buf);
604 struct environ_data {
605 union control *varbox, *valbox, *addbutton, *rembutton, *listbox;
608 static void environ_handler(union control *ctrl, void *dlg,
609 void *data, int event)
611 Config *cfg = (Config *)data;
612 struct environ_data *ed =
613 (struct environ_data *)ctrl->generic.context.p;
615 if (event == EVENT_REFRESH) {
616 if (ctrl == ed->listbox) {
617 char *p = cfg->environmt;
618 dlg_update_start(ctrl, dlg);
619 dlg_listbox_clear(ctrl, dlg);
621 dlg_listbox_add(ctrl, dlg, p);
624 dlg_update_done(ctrl, dlg);
626 } else if (event == EVENT_ACTION) {
627 if (ctrl == ed->addbutton) {
628 char str[sizeof(cfg->environmt)];
630 dlg_editbox_get(ed->varbox, dlg, str, sizeof(str)-1);
635 p = str + strlen(str);
637 dlg_editbox_get(ed->valbox, dlg, p, sizeof(str)-1 - (p - str));
648 if ((p - cfg->environmt) + strlen(str) + 2 <
649 sizeof(cfg->environmt)) {
651 p[strlen(str) + 1] = '\0';
652 dlg_listbox_add(ed->listbox, dlg, str);
653 dlg_editbox_set(ed->varbox, dlg, "");
654 dlg_editbox_set(ed->valbox, dlg, "");
656 dlg_error_msg(dlg, "Environment too big");
658 } else if (ctrl == ed->rembutton) {
659 int i = dlg_listbox_index(ed->listbox, dlg);
665 dlg_listbox_del(ed->listbox, dlg, i);
693 struct portfwd_data {
694 union control *addbutton, *rembutton, *listbox;
695 union control *sourcebox, *destbox, *direction;
697 union control *addressfamily;
701 static void portfwd_handler(union control *ctrl, void *dlg,
702 void *data, int event)
704 Config *cfg = (Config *)data;
705 struct portfwd_data *pfd =
706 (struct portfwd_data *)ctrl->generic.context.p;
708 if (event == EVENT_REFRESH) {
709 if (ctrl == pfd->listbox) {
710 char *p = cfg->portfwd;
711 dlg_update_start(ctrl, dlg);
712 dlg_listbox_clear(ctrl, dlg);
714 dlg_listbox_add(ctrl, dlg, p);
717 dlg_update_done(ctrl, dlg);
718 } else if (ctrl == pfd->direction) {
722 dlg_radiobutton_set(ctrl, dlg, 0);
724 } else if (ctrl == pfd->addressfamily) {
725 dlg_radiobutton_set(ctrl, dlg, 0);
728 } else if (event == EVENT_ACTION) {
729 if (ctrl == pfd->addbutton) {
730 char str[sizeof(cfg->portfwd)];
737 whichbutton = dlg_radiobutton_get(pfd->addressfamily, dlg);
738 if (whichbutton == 1)
740 else if (whichbutton == 2)
744 whichbutton = dlg_radiobutton_get(pfd->direction, dlg);
745 if (whichbutton == 0)
747 else if (whichbutton == 1)
753 dlg_editbox_get(pfd->sourcebox, dlg, str+i, sizeof(str) - i);
755 dlg_error_msg(dlg, "You need to specify a source port number");
758 p = str + strlen(str);
761 dlg_editbox_get(pfd->destbox, dlg, p,
762 sizeof(str) - (p - str));
763 if (!*p || !strchr(p, ':')) {
765 "You need to specify a destination address\n"
766 "in the form \"host.name:port\"");
777 if ((p - cfg->portfwd) + strlen(str) + 2 <=
778 sizeof(cfg->portfwd)) {
780 p[strlen(str) + 1] = '\0';
781 dlg_listbox_add(pfd->listbox, dlg, str);
782 dlg_editbox_set(pfd->sourcebox, dlg, "");
783 dlg_editbox_set(pfd->destbox, dlg, "");
785 dlg_error_msg(dlg, "Too many forwardings");
787 } else if (ctrl == pfd->rembutton) {
788 int i = dlg_listbox_index(pfd->listbox, dlg);
794 dlg_listbox_del(pfd->listbox, dlg, i);
822 void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
823 int midsession, int protocol, int protcfginfo)
825 struct controlset *s;
826 struct sessionsaver_data *ssd;
827 struct charclass_data *ccd;
828 struct colour_data *cd;
829 struct environ_data *ed;
830 struct portfwd_data *pfd;
834 ssd = (struct sessionsaver_data *)
835 ctrl_alloc(b, sizeof(struct sessionsaver_data));
836 memset(ssd, 0, sizeof(*ssd));
837 ssd->midsession = midsession;
840 * The standard panel that appears at the bottom of all panels:
841 * Open, Cancel, Apply etc.
843 s = ctrl_getset(b, "", "", "");
844 ctrl_columns(s, 5, 20, 20, 20, 20, 20);
845 ssd->okbutton = ctrl_pushbutton(s,
846 (midsession ? "Apply" : "Open"),
847 (char)(midsession ? 'a' : 'o'),
849 sessionsaver_handler, P(ssd));
850 ssd->okbutton->button.isdefault = TRUE;
851 ssd->okbutton->generic.column = 3;
852 ssd->cancelbutton = ctrl_pushbutton(s, "Cancel", 'c', HELPCTX(no_help),
853 sessionsaver_handler, P(ssd));
854 ssd->cancelbutton->button.iscancel = TRUE;
855 ssd->cancelbutton->generic.column = 4;
856 /* We carefully don't close the 5-column part, so that platform-
857 * specific add-ons can put extra buttons alongside Open and Cancel. */
862 str = dupprintf("Basic options for your %s session", appname);
863 ctrl_settitle(b, "Session", str);
867 s = ctrl_getset(b, "Session", "hostport",
868 "Specify your connection by host name or IP address");
869 ctrl_columns(s, 2, 75, 25);
870 c = ctrl_editbox(s, "Host Name (or IP address)", 'n', 100,
871 HELPCTX(session_hostname),
872 dlg_stdeditbox_handler, I(offsetof(Config,host)),
873 I(sizeof(((Config *)0)->host)));
874 c->generic.column = 0;
875 c = ctrl_editbox(s, "Port", 'p', 100, HELPCTX(session_hostname),
876 dlg_stdeditbox_handler,
877 I(offsetof(Config,port)), I(-1));
878 c->generic.column = 1;
879 ctrl_columns(s, 1, 100);
880 if (backends[3].name == NULL) {
881 ctrl_radiobuttons(s, "Protocol:", NO_SHORTCUT, 3,
882 HELPCTX(session_hostname),
883 protocolbuttons_handler, P(c),
884 "Raw", 'r', I(PROT_RAW),
885 "Telnet", 't', I(PROT_TELNET),
886 "Rlogin", 'i', I(PROT_RLOGIN),
889 ctrl_radiobuttons(s, "Protocol:", NO_SHORTCUT, 4,
890 HELPCTX(session_hostname),
891 protocolbuttons_handler, P(c),
892 "Raw", 'r', I(PROT_RAW),
893 "Telnet", 't', I(PROT_TELNET),
894 "Rlogin", 'i', I(PROT_RLOGIN),
895 "SSH", 's', I(PROT_SSH),
901 * The Load/Save panel is available even in mid-session.
903 s = ctrl_getset(b, "Session", "savedsessions",
904 midsession ? "Save the current session settings" :
905 "Load, save or delete a stored session");
906 ctrl_columns(s, 2, 75, 25);
907 ssd->sesslist = sesslist;
908 ssd->editbox = ctrl_editbox(s, "Saved Sessions", 'e', 100,
909 HELPCTX(session_saved),
910 sessionsaver_handler, P(ssd), P(NULL));
911 ssd->editbox->generic.column = 0;
912 /* Reset columns so that the buttons are alongside the list, rather
913 * than alongside that edit box. */
914 ctrl_columns(s, 1, 100);
915 ctrl_columns(s, 2, 75, 25);
916 ssd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
917 HELPCTX(session_saved),
918 sessionsaver_handler, P(ssd));
919 ssd->listbox->generic.column = 0;
920 ssd->listbox->listbox.height = 7;
922 ssd->loadbutton = ctrl_pushbutton(s, "Load", 'l',
923 HELPCTX(session_saved),
924 sessionsaver_handler, P(ssd));
925 ssd->loadbutton->generic.column = 1;
927 /* We can't offer the Load button mid-session, as it would allow the
928 * user to load and subsequently save settings they can't see. (And
929 * also change otherwise immutable settings underfoot; that probably
930 * shouldn't be a problem, but.) */
931 ssd->loadbutton = NULL;
933 /* "Save" button is permitted mid-session. */
934 ssd->savebutton = ctrl_pushbutton(s, "Save", 'v',
935 HELPCTX(session_saved),
936 sessionsaver_handler, P(ssd));
937 ssd->savebutton->generic.column = 1;
939 ssd->delbutton = ctrl_pushbutton(s, "Delete", 'd',
940 HELPCTX(session_saved),
941 sessionsaver_handler, P(ssd));
942 ssd->delbutton->generic.column = 1;
944 /* Disable the Delete button mid-session too, for UI consistency. */
945 ssd->delbutton = NULL;
947 ctrl_columns(s, 1, 100);
949 s = ctrl_getset(b, "Session", "otheropts", NULL);
950 c = ctrl_radiobuttons(s, "Close window on exit:", 'w', 4,
951 HELPCTX(session_coe),
952 dlg_stdradiobutton_handler,
953 I(offsetof(Config, close_on_exit)),
954 "Always", I(FORCE_ON),
955 "Never", I(FORCE_OFF),
956 "Only on clean exit", I(AUTO), NULL);
959 * The Session/Logging panel.
961 ctrl_settitle(b, "Session/Logging", "Options controlling session logging");
963 s = ctrl_getset(b, "Session/Logging", "main", NULL);
965 * The logging buttons change depending on whether SSH packet
966 * logging can sensibly be available.
970 if ((midsession && protocol == PROT_SSH) ||
971 (!midsession && backends[3].name != NULL))
972 sshlogname = "Log SSH packet data";
974 sshlogname = NULL; /* this will disable the button */
975 ctrl_radiobuttons(s, "Session logging:", NO_SHORTCUT, 1,
976 HELPCTX(logging_main),
977 loggingbuttons_handler,
978 I(offsetof(Config, logtype)),
979 "Logging turned off completely", 't', I(LGTYP_NONE),
980 "Log printable output only", 'p', I(LGTYP_ASCII),
981 "Log all session output", 'l', I(LGTYP_DEBUG),
982 sshlogname, 's', I(LGTYP_PACKETS),
985 ctrl_filesel(s, "Log file name:", 'f',
986 NULL, TRUE, "Select session log file name",
987 HELPCTX(logging_filename),
988 dlg_stdfilesel_handler, I(offsetof(Config, logfilename)));
989 ctrl_text(s, "(Log file name can contain &Y, &M, &D for date,"
990 " &T for time, and &H for host name)",
991 HELPCTX(logging_filename));
992 ctrl_radiobuttons(s, "What to do if the log file already exists:", 'e', 1,
993 HELPCTX(logging_exists),
994 dlg_stdradiobutton_handler, I(offsetof(Config,logxfovr)),
995 "Always overwrite it", I(LGXF_OVR),
996 "Always append to the end of it", I(LGXF_APN),
997 "Ask the user every time", I(LGXF_ASK), NULL);
998 ctrl_checkbox(s, "Flush log file frequently", 'u',
999 HELPCTX(logging_flush),
1000 dlg_stdcheckbox_handler, I(offsetof(Config,logflush)));
1002 if ((midsession && protocol == PROT_SSH) ||
1003 (!midsession && backends[3].name != NULL)) {
1004 s = ctrl_getset(b, "Session/Logging", "ssh",
1005 "Options specific to SSH packet logging");
1006 ctrl_checkbox(s, "Omit known password fields", 'k',
1007 HELPCTX(logging_ssh_omit_password),
1008 dlg_stdcheckbox_handler, I(offsetof(Config,logomitpass)));
1009 ctrl_checkbox(s, "Omit session data", 'd',
1010 HELPCTX(logging_ssh_omit_data),
1011 dlg_stdcheckbox_handler, I(offsetof(Config,logomitdata)));
1015 * The Terminal panel.
1017 ctrl_settitle(b, "Terminal", "Options controlling the terminal emulation");
1019 s = ctrl_getset(b, "Terminal", "general", "Set various terminal options");
1020 ctrl_checkbox(s, "Auto wrap mode initially on", 'w',
1021 HELPCTX(terminal_autowrap),
1022 dlg_stdcheckbox_handler, I(offsetof(Config,wrap_mode)));
1023 ctrl_checkbox(s, "DEC Origin Mode initially on", 'd',
1024 HELPCTX(terminal_decom),
1025 dlg_stdcheckbox_handler, I(offsetof(Config,dec_om)));
1026 ctrl_checkbox(s, "Implicit CR in every LF", 'r',
1027 HELPCTX(terminal_lfhascr),
1028 dlg_stdcheckbox_handler, I(offsetof(Config,lfhascr)));
1029 ctrl_checkbox(s, "Use background colour to erase screen", 'e',
1030 HELPCTX(terminal_bce),
1031 dlg_stdcheckbox_handler, I(offsetof(Config,bce)));
1032 ctrl_checkbox(s, "Enable blinking text", 'n',
1033 HELPCTX(terminal_blink),
1034 dlg_stdcheckbox_handler, I(offsetof(Config,blinktext)));
1035 ctrl_editbox(s, "Answerback to ^E:", 's', 100,
1036 HELPCTX(terminal_answerback),
1037 dlg_stdeditbox_handler, I(offsetof(Config,answerback)),
1038 I(sizeof(((Config *)0)->answerback)));
1040 s = ctrl_getset(b, "Terminal", "ldisc", "Line discipline options");
1041 ctrl_radiobuttons(s, "Local echo:", 'l', 3,
1042 HELPCTX(terminal_localecho),
1043 dlg_stdradiobutton_handler,I(offsetof(Config,localecho)),
1045 "Force on", I(FORCE_ON),
1046 "Force off", I(FORCE_OFF), NULL);
1047 ctrl_radiobuttons(s, "Local line editing:", 't', 3,
1048 HELPCTX(terminal_localedit),
1049 dlg_stdradiobutton_handler,I(offsetof(Config,localedit)),
1051 "Force on", I(FORCE_ON),
1052 "Force off", I(FORCE_OFF), NULL);
1054 s = ctrl_getset(b, "Terminal", "printing", "Remote-controlled printing");
1055 ctrl_combobox(s, "Printer to send ANSI printer output to:", 'p', 100,
1056 HELPCTX(terminal_printing),
1057 printerbox_handler, P(NULL), P(NULL));
1060 * The Terminal/Keyboard panel.
1062 ctrl_settitle(b, "Terminal/Keyboard",
1063 "Options controlling the effects of keys");
1065 s = ctrl_getset(b, "Terminal/Keyboard", "mappings",
1066 "Change the sequences sent by:");
1067 ctrl_radiobuttons(s, "The Backspace key", 'b', 2,
1068 HELPCTX(keyboard_backspace),
1069 dlg_stdradiobutton_handler,
1070 I(offsetof(Config, bksp_is_delete)),
1071 "Control-H", I(0), "Control-? (127)", I(1), NULL);
1072 ctrl_radiobuttons(s, "The Home and End keys", 'e', 2,
1073 HELPCTX(keyboard_homeend),
1074 dlg_stdradiobutton_handler,
1075 I(offsetof(Config, rxvt_homeend)),
1076 "Standard", I(0), "rxvt", I(1), NULL);
1077 ctrl_radiobuttons(s, "The Function keys and keypad", 'f', 3,
1078 HELPCTX(keyboard_funkeys),
1079 dlg_stdradiobutton_handler,
1080 I(offsetof(Config, funky_type)),
1081 "ESC[n~", I(0), "Linux", I(1), "Xterm R6", I(2),
1082 "VT400", I(3), "VT100+", I(4), "SCO", I(5), NULL);
1084 s = ctrl_getset(b, "Terminal/Keyboard", "appkeypad",
1085 "Application keypad settings:");
1086 ctrl_radiobuttons(s, "Initial state of cursor keys:", 'r', 3,
1087 HELPCTX(keyboard_appcursor),
1088 dlg_stdradiobutton_handler,
1089 I(offsetof(Config, app_cursor)),
1090 "Normal", I(0), "Application", I(1), NULL);
1091 ctrl_radiobuttons(s, "Initial state of numeric keypad:", 'n', 3,
1092 HELPCTX(keyboard_appkeypad),
1093 numeric_keypad_handler, P(NULL),
1094 "Normal", I(0), "Application", I(1), "NetHack", I(2),
1098 * The Terminal/Bell panel.
1100 ctrl_settitle(b, "Terminal/Bell",
1101 "Options controlling the terminal bell");
1103 s = ctrl_getset(b, "Terminal/Bell", "style", "Set the style of bell");
1104 ctrl_radiobuttons(s, "Action to happen when a bell occurs:", 'b', 1,
1105 HELPCTX(bell_style),
1106 dlg_stdradiobutton_handler, I(offsetof(Config, beep)),
1107 "None (bell disabled)", I(BELL_DISABLED),
1108 "Make default system alert sound", I(BELL_DEFAULT),
1109 "Visual bell (flash window)", I(BELL_VISUAL), NULL);
1111 s = ctrl_getset(b, "Terminal/Bell", "overload",
1112 "Control the bell overload behaviour");
1113 ctrl_checkbox(s, "Bell is temporarily disabled when over-used", 'd',
1114 HELPCTX(bell_overload),
1115 dlg_stdcheckbox_handler, I(offsetof(Config,bellovl)));
1116 ctrl_editbox(s, "Over-use means this many bells...", 'm', 20,
1117 HELPCTX(bell_overload),
1118 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_n)), I(-1));
1119 ctrl_editbox(s, "... in this many seconds", 't', 20,
1120 HELPCTX(bell_overload),
1121 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_t)),
1123 ctrl_text(s, "The bell is re-enabled after a few seconds of silence.",
1124 HELPCTX(bell_overload));
1125 ctrl_editbox(s, "Seconds of silence required", 's', 20,
1126 HELPCTX(bell_overload),
1127 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_s)),
1131 * The Terminal/Features panel.
1133 ctrl_settitle(b, "Terminal/Features",
1134 "Enabling and disabling advanced terminal features");
1136 s = ctrl_getset(b, "Terminal/Features", "main", NULL);
1137 ctrl_checkbox(s, "Disable application cursor keys mode", 'u',
1138 HELPCTX(features_application),
1139 dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_c)));
1140 ctrl_checkbox(s, "Disable application keypad mode", 'k',
1141 HELPCTX(features_application),
1142 dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_k)));
1143 ctrl_checkbox(s, "Disable xterm-style mouse reporting", 'x',
1144 HELPCTX(features_mouse),
1145 dlg_stdcheckbox_handler, I(offsetof(Config,no_mouse_rep)));
1146 ctrl_checkbox(s, "Disable remote-controlled terminal resizing", 's',
1147 HELPCTX(features_resize),
1148 dlg_stdcheckbox_handler,
1149 I(offsetof(Config,no_remote_resize)));
1150 ctrl_checkbox(s, "Disable switching to alternate terminal screen", 'w',
1151 HELPCTX(features_altscreen),
1152 dlg_stdcheckbox_handler, I(offsetof(Config,no_alt_screen)));
1153 ctrl_checkbox(s, "Disable remote-controlled window title changing", 't',
1154 HELPCTX(features_retitle),
1155 dlg_stdcheckbox_handler,
1156 I(offsetof(Config,no_remote_wintitle)));
1157 ctrl_checkbox(s, "Disable remote window title querying (SECURITY)",
1158 'q', HELPCTX(features_qtitle), dlg_stdcheckbox_handler,
1159 I(offsetof(Config,no_remote_qtitle)));
1160 ctrl_checkbox(s, "Disable destructive backspace on server sending ^?",'b',
1161 HELPCTX(features_dbackspace),
1162 dlg_stdcheckbox_handler, I(offsetof(Config,no_dbackspace)));
1163 ctrl_checkbox(s, "Disable remote-controlled character set configuration",
1164 'r', HELPCTX(features_charset), dlg_stdcheckbox_handler,
1165 I(offsetof(Config,no_remote_charset)));
1166 ctrl_checkbox(s, "Disable Arabic text shaping",
1167 'l', HELPCTX(features_arabicshaping), dlg_stdcheckbox_handler,
1168 I(offsetof(Config, arabicshaping)));
1169 ctrl_checkbox(s, "Disable bidirectional text display",
1170 'd', HELPCTX(features_bidi), dlg_stdcheckbox_handler,
1171 I(offsetof(Config, bidi)));
1176 str = dupprintf("Options controlling %s's window", appname);
1177 ctrl_settitle(b, "Window", str);
1180 s = ctrl_getset(b, "Window", "size", "Set the size of the window");
1181 ctrl_columns(s, 2, 50, 50);
1182 c = ctrl_editbox(s, "Rows", 'r', 100,
1183 HELPCTX(window_size),
1184 dlg_stdeditbox_handler, I(offsetof(Config,height)),I(-1));
1185 c->generic.column = 0;
1186 c = ctrl_editbox(s, "Columns", 'm', 100,
1187 HELPCTX(window_size),
1188 dlg_stdeditbox_handler, I(offsetof(Config,width)), I(-1));
1189 c->generic.column = 1;
1190 ctrl_columns(s, 1, 100);
1192 s = ctrl_getset(b, "Window", "scrollback",
1193 "Control the scrollback in the window");
1194 ctrl_editbox(s, "Lines of scrollback", 's', 50,
1195 HELPCTX(window_scrollback),
1196 dlg_stdeditbox_handler, I(offsetof(Config,savelines)), I(-1));
1197 ctrl_checkbox(s, "Display scrollbar", 'd',
1198 HELPCTX(window_scrollback),
1199 dlg_stdcheckbox_handler, I(offsetof(Config,scrollbar)));
1200 ctrl_checkbox(s, "Reset scrollback on keypress", 'k',
1201 HELPCTX(window_scrollback),
1202 dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_key)));
1203 ctrl_checkbox(s, "Reset scrollback on display activity", 'p',
1204 HELPCTX(window_scrollback),
1205 dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_disp)));
1206 ctrl_checkbox(s, "Push erased text into scrollback", 'e',
1207 HELPCTX(window_erased),
1208 dlg_stdcheckbox_handler,
1209 I(offsetof(Config,erase_to_scrollback)));
1212 * The Window/Appearance panel.
1214 str = dupprintf("Configure the appearance of %s's window", appname);
1215 ctrl_settitle(b, "Window/Appearance", str);
1218 s = ctrl_getset(b, "Window/Appearance", "cursor",
1219 "Adjust the use of the cursor");
1220 ctrl_radiobuttons(s, "Cursor appearance:", NO_SHORTCUT, 3,
1221 HELPCTX(appearance_cursor),
1222 dlg_stdradiobutton_handler,
1223 I(offsetof(Config, cursor_type)),
1225 "Underline", 'u', I(1),
1226 "Vertical line", 'v', I(2), NULL);
1227 ctrl_checkbox(s, "Cursor blinks", 'b',
1228 HELPCTX(appearance_cursor),
1229 dlg_stdcheckbox_handler, I(offsetof(Config,blink_cur)));
1231 s = ctrl_getset(b, "Window/Appearance", "font",
1233 ctrl_fontsel(s, "Font used in the terminal window", 'n',
1234 HELPCTX(appearance_font),
1235 dlg_stdfontsel_handler, I(offsetof(Config, font)));
1237 s = ctrl_getset(b, "Window/Appearance", "mouse",
1238 "Adjust the use of the mouse pointer");
1239 ctrl_checkbox(s, "Hide mouse pointer when typing in window", 'p',
1240 HELPCTX(appearance_hidemouse),
1241 dlg_stdcheckbox_handler, I(offsetof(Config,hide_mouseptr)));
1243 s = ctrl_getset(b, "Window/Appearance", "border",
1244 "Adjust the window border");
1245 ctrl_editbox(s, "Gap between text and window edge:", NO_SHORTCUT, 20,
1246 HELPCTX(appearance_border),
1247 dlg_stdeditbox_handler,
1248 I(offsetof(Config,window_border)), I(-1));
1251 * The Window/Behaviour panel.
1253 str = dupprintf("Configure the behaviour of %s's window", appname);
1254 ctrl_settitle(b, "Window/Behaviour", str);
1257 s = ctrl_getset(b, "Window/Behaviour", "title",
1258 "Adjust the behaviour of the window title");
1259 ctrl_editbox(s, "Window title:", 't', 100,
1260 HELPCTX(appearance_title),
1261 dlg_stdeditbox_handler, I(offsetof(Config,wintitle)),
1262 I(sizeof(((Config *)0)->wintitle)));
1263 ctrl_checkbox(s, "Separate window and icon titles", 'i',
1264 HELPCTX(appearance_title),
1265 dlg_stdcheckbox_handler,
1266 I(CHECKBOX_INVERT | offsetof(Config,win_name_always)));
1268 s = ctrl_getset(b, "Window/Behaviour", "main", NULL);
1269 ctrl_checkbox(s, "Warn before closing window", 'w',
1270 HELPCTX(behaviour_closewarn),
1271 dlg_stdcheckbox_handler, I(offsetof(Config,warn_on_close)));
1274 * The Window/Translation panel.
1276 ctrl_settitle(b, "Window/Translation",
1277 "Options controlling character set translation");
1279 s = ctrl_getset(b, "Window/Translation", "trans",
1280 "Character set translation on received data");
1281 ctrl_combobox(s, "Received data assumed to be in which character set:",
1282 'r', 100, HELPCTX(translation_codepage),
1283 codepage_handler, P(NULL), P(NULL));
1285 s = ctrl_getset(b, "Window/Translation", "tweaks", NULL);
1286 ctrl_checkbox(s, "Treat CJK ambiguous characters as wide", 'w',
1287 HELPCTX(translation_cjk_ambig_wide),
1288 dlg_stdcheckbox_handler, I(offsetof(Config,cjk_ambig_wide)));
1290 str = dupprintf("Adjust how %s handles line drawing characters", appname);
1291 s = ctrl_getset(b, "Window/Translation", "linedraw", str);
1293 ctrl_radiobuttons(s, "Handling of line drawing characters:", NO_SHORTCUT,1,
1294 HELPCTX(translation_linedraw),
1295 dlg_stdradiobutton_handler,
1296 I(offsetof(Config, vtmode)),
1297 "Use Unicode line drawing code points",'u',I(VT_UNICODE),
1298 "Poor man's line drawing (+, - and |)",'p',I(VT_POORMAN),
1300 ctrl_checkbox(s, "Copy and paste line drawing characters as lqqqk",'d',
1301 HELPCTX(selection_linedraw),
1302 dlg_stdcheckbox_handler, I(offsetof(Config,rawcnp)));
1305 * The Window/Selection panel.
1307 ctrl_settitle(b, "Window/Selection", "Options controlling copy and paste");
1309 s = ctrl_getset(b, "Window/Selection", "mouse",
1310 "Control use of mouse");
1311 ctrl_checkbox(s, "Shift overrides application's use of mouse", 'p',
1312 HELPCTX(selection_shiftdrag),
1313 dlg_stdcheckbox_handler, I(offsetof(Config,mouse_override)));
1314 ctrl_radiobuttons(s,
1315 "Default selection mode (Alt+drag does the other one):",
1317 HELPCTX(selection_rect),
1318 dlg_stdradiobutton_handler,
1319 I(offsetof(Config, rect_select)),
1320 "Normal", 'n', I(0),
1321 "Rectangular block", 'r', I(1), NULL);
1323 s = ctrl_getset(b, "Window/Selection", "charclass",
1324 "Control the select-one-word-at-a-time mode");
1325 ccd = (struct charclass_data *)
1326 ctrl_alloc(b, sizeof(struct charclass_data));
1327 ccd->listbox = ctrl_listbox(s, "Character classes:", 'e',
1328 HELPCTX(selection_charclasses),
1329 charclass_handler, P(ccd));
1330 ccd->listbox->listbox.multisel = 1;
1331 ccd->listbox->listbox.ncols = 4;
1332 ccd->listbox->listbox.percentages = snewn(4, int);
1333 ccd->listbox->listbox.percentages[0] = 15;
1334 ccd->listbox->listbox.percentages[1] = 25;
1335 ccd->listbox->listbox.percentages[2] = 20;
1336 ccd->listbox->listbox.percentages[3] = 40;
1337 ctrl_columns(s, 2, 67, 33);
1338 ccd->editbox = ctrl_editbox(s, "Set to class", 't', 50,
1339 HELPCTX(selection_charclasses),
1340 charclass_handler, P(ccd), P(NULL));
1341 ccd->editbox->generic.column = 0;
1342 ccd->button = ctrl_pushbutton(s, "Set", 's',
1343 HELPCTX(selection_charclasses),
1344 charclass_handler, P(ccd));
1345 ccd->button->generic.column = 1;
1346 ctrl_columns(s, 1, 100);
1349 * The Window/Colours panel.
1351 ctrl_settitle(b, "Window/Colours", "Options controlling use of colours");
1353 s = ctrl_getset(b, "Window/Colours", "general",
1354 "General options for colour usage");
1355 ctrl_checkbox(s, "Allow terminal to specify ANSI colours", 'i',
1356 HELPCTX(colours_ansi),
1357 dlg_stdcheckbox_handler, I(offsetof(Config,ansi_colour)));
1358 ctrl_checkbox(s, "Allow terminal to use xterm 256-colour mode", '2',
1359 HELPCTX(colours_xterm256), dlg_stdcheckbox_handler,
1360 I(offsetof(Config,xterm_256_colour)));
1361 ctrl_checkbox(s, "Bolded text is a different colour", 'b',
1362 HELPCTX(colours_bold),
1363 dlg_stdcheckbox_handler, I(offsetof(Config,bold_colour)));
1365 str = dupprintf("Adjust the precise colours %s displays", appname);
1366 s = ctrl_getset(b, "Window/Colours", "adjust", str);
1368 ctrl_text(s, "Select a colour from the list, and then click the"
1369 " Modify button to change its appearance.",
1370 HELPCTX(colours_config));
1371 ctrl_columns(s, 2, 67, 33);
1372 cd = (struct colour_data *)ctrl_alloc(b, sizeof(struct colour_data));
1373 cd->listbox = ctrl_listbox(s, "Select a colour to adjust:", 'u',
1374 HELPCTX(colours_config), colour_handler, P(cd));
1375 cd->listbox->generic.column = 0;
1376 cd->listbox->listbox.height = 7;
1377 c = ctrl_text(s, "RGB value:", HELPCTX(colours_config));
1378 c->generic.column = 1;
1379 cd->redit = ctrl_editbox(s, "Red", 'r', 50, HELPCTX(colours_config),
1380 colour_handler, P(cd), P(NULL));
1381 cd->redit->generic.column = 1;
1382 cd->gedit = ctrl_editbox(s, "Green", 'n', 50, HELPCTX(colours_config),
1383 colour_handler, P(cd), P(NULL));
1384 cd->gedit->generic.column = 1;
1385 cd->bedit = ctrl_editbox(s, "Blue", 'e', 50, HELPCTX(colours_config),
1386 colour_handler, P(cd), P(NULL));
1387 cd->bedit->generic.column = 1;
1388 cd->button = ctrl_pushbutton(s, "Modify", 'm', HELPCTX(colours_config),
1389 colour_handler, P(cd));
1390 cd->button->generic.column = 1;
1391 ctrl_columns(s, 1, 100);
1394 * The Connection panel. This doesn't show up if we're in a
1395 * non-network utility such as pterm. We tell this by being
1396 * passed a protocol < 0.
1398 if (protocol >= 0) {
1399 ctrl_settitle(b, "Connection", "Options controlling the connection");
1401 s = ctrl_getset(b, "Connection", "keepalive",
1402 "Sending of null packets to keep session active");
1403 ctrl_editbox(s, "Seconds between keepalives (0 to turn off)", 'k', 20,
1404 HELPCTX(connection_keepalive),
1405 dlg_stdeditbox_handler, I(offsetof(Config,ping_interval)),
1409 s = ctrl_getset(b, "Connection", "tcp",
1410 "Low-level TCP connection options");
1411 ctrl_checkbox(s, "Disable Nagle's algorithm (TCP_NODELAY option)",
1412 'n', HELPCTX(connection_nodelay),
1413 dlg_stdcheckbox_handler,
1414 I(offsetof(Config,tcp_nodelay)));
1415 ctrl_checkbox(s, "Enable TCP keepalives (SO_KEEPALIVE option)",
1416 'p', HELPCTX(connection_tcpkeepalive),
1417 dlg_stdcheckbox_handler,
1418 I(offsetof(Config,tcp_keepalives)));
1420 s = ctrl_getset(b, "Connection", "ipversion",
1421 "Internet protocol version");
1422 ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
1423 HELPCTX(connection_ipversion),
1424 dlg_stdradiobutton_handler,
1425 I(offsetof(Config, addressfamily)),
1426 "Auto", NO_SHORTCUT, I(ADDRTYPE_UNSPEC),
1427 "IPv4", NO_SHORTCUT, I(ADDRTYPE_IPV4),
1428 "IPv6", NO_SHORTCUT, I(ADDRTYPE_IPV6),
1434 * A sub-panel Connection/Data, containing options that
1435 * decide on data to send to the server.
1438 ctrl_settitle(b, "Connection/Data", "Data to send to the server");
1440 s = ctrl_getset(b, "Connection/Data", "login",
1442 ctrl_editbox(s, "Auto-login username", 'u', 50,
1443 HELPCTX(connection_username),
1444 dlg_stdeditbox_handler, I(offsetof(Config,username)),
1445 I(sizeof(((Config *)0)->username)));
1447 s = ctrl_getset(b, "Connection/Data", "term",
1448 "Terminal details");
1449 ctrl_editbox(s, "Terminal-type string", 't', 50,
1450 HELPCTX(connection_termtype),
1451 dlg_stdeditbox_handler, I(offsetof(Config,termtype)),
1452 I(sizeof(((Config *)0)->termtype)));
1453 ctrl_editbox(s, "Terminal speeds", 's', 50,
1454 HELPCTX(connection_termspeed),
1455 dlg_stdeditbox_handler, I(offsetof(Config,termspeed)),
1456 I(sizeof(((Config *)0)->termspeed)));
1458 s = ctrl_getset(b, "Connection/Data", "env",
1459 "Environment variables");
1460 ctrl_columns(s, 2, 80, 20);
1461 ed = (struct environ_data *)
1462 ctrl_alloc(b, sizeof(struct environ_data));
1463 ed->varbox = ctrl_editbox(s, "Variable", 'v', 60,
1464 HELPCTX(telnet_environ),
1465 environ_handler, P(ed), P(NULL));
1466 ed->varbox->generic.column = 0;
1467 ed->valbox = ctrl_editbox(s, "Value", 'l', 60,
1468 HELPCTX(telnet_environ),
1469 environ_handler, P(ed), P(NULL));
1470 ed->valbox->generic.column = 0;
1471 ed->addbutton = ctrl_pushbutton(s, "Add", 'd',
1472 HELPCTX(telnet_environ),
1473 environ_handler, P(ed));
1474 ed->addbutton->generic.column = 1;
1475 ed->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1476 HELPCTX(telnet_environ),
1477 environ_handler, P(ed));
1478 ed->rembutton->generic.column = 1;
1479 ctrl_columns(s, 1, 100);
1480 ed->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1481 HELPCTX(telnet_environ),
1482 environ_handler, P(ed));
1483 ed->listbox->listbox.height = 3;
1484 ed->listbox->listbox.ncols = 2;
1485 ed->listbox->listbox.percentages = snewn(2, int);
1486 ed->listbox->listbox.percentages[0] = 30;
1487 ed->listbox->listbox.percentages[1] = 70;
1494 * The Connection/Proxy panel.
1496 ctrl_settitle(b, "Connection/Proxy",
1497 "Options controlling proxy usage");
1499 s = ctrl_getset(b, "Connection/Proxy", "basics", NULL);
1500 ctrl_radiobuttons(s, "Proxy type:", 't', 3,
1501 HELPCTX(proxy_type),
1502 dlg_stdradiobutton_handler,
1503 I(offsetof(Config, proxy_type)),
1504 "None", I(PROXY_NONE),
1505 "SOCKS 4", I(PROXY_SOCKS4),
1506 "SOCKS 5", I(PROXY_SOCKS5),
1507 "HTTP", I(PROXY_HTTP),
1508 "Telnet", I(PROXY_TELNET),
1510 ctrl_columns(s, 2, 80, 20);
1511 c = ctrl_editbox(s, "Proxy hostname", 'y', 100,
1512 HELPCTX(proxy_main),
1513 dlg_stdeditbox_handler,
1514 I(offsetof(Config,proxy_host)),
1515 I(sizeof(((Config *)0)->proxy_host)));
1516 c->generic.column = 0;
1517 c = ctrl_editbox(s, "Port", 'p', 100,
1518 HELPCTX(proxy_main),
1519 dlg_stdeditbox_handler,
1520 I(offsetof(Config,proxy_port)),
1522 c->generic.column = 1;
1523 ctrl_columns(s, 1, 100);
1524 ctrl_editbox(s, "Exclude Hosts/IPs", 'e', 100,
1525 HELPCTX(proxy_exclude),
1526 dlg_stdeditbox_handler,
1527 I(offsetof(Config,proxy_exclude_list)),
1528 I(sizeof(((Config *)0)->proxy_exclude_list)));
1529 ctrl_checkbox(s, "Consider proxying local host connections", 'x',
1530 HELPCTX(proxy_exclude),
1531 dlg_stdcheckbox_handler,
1532 I(offsetof(Config,even_proxy_localhost)));
1533 ctrl_radiobuttons(s, "Do DNS name lookup at proxy end:", 'd', 3,
1535 dlg_stdradiobutton_handler,
1536 I(offsetof(Config, proxy_dns)),
1539 "Yes", I(FORCE_ON), NULL);
1540 ctrl_editbox(s, "Username", 'u', 60,
1541 HELPCTX(proxy_auth),
1542 dlg_stdeditbox_handler,
1543 I(offsetof(Config,proxy_username)),
1544 I(sizeof(((Config *)0)->proxy_username)));
1545 c = ctrl_editbox(s, "Password", 'w', 60,
1546 HELPCTX(proxy_auth),
1547 dlg_stdeditbox_handler,
1548 I(offsetof(Config,proxy_password)),
1549 I(sizeof(((Config *)0)->proxy_password)));
1550 c->editbox.password = 1;
1551 ctrl_editbox(s, "Telnet command", 'm', 100,
1552 HELPCTX(proxy_command),
1553 dlg_stdeditbox_handler,
1554 I(offsetof(Config,proxy_telnet_command)),
1555 I(sizeof(((Config *)0)->proxy_telnet_command)));
1559 * The Telnet panel exists in the base config box, and in a
1560 * mid-session reconfig box _if_ we're using Telnet.
1562 if (!midsession || protocol == PROT_TELNET) {
1564 * The Connection/Telnet panel.
1566 ctrl_settitle(b, "Connection/Telnet",
1567 "Options controlling Telnet connections");
1569 s = ctrl_getset(b, "Connection/Telnet", "protocol",
1570 "Telnet protocol adjustments");
1573 ctrl_radiobuttons(s, "Handling of OLD_ENVIRON ambiguity:",
1575 HELPCTX(telnet_oldenviron),
1576 dlg_stdradiobutton_handler,
1577 I(offsetof(Config, rfc_environ)),
1578 "BSD (commonplace)", 'b', I(0),
1579 "RFC 1408 (unusual)", 'f', I(1), NULL);
1580 ctrl_radiobuttons(s, "Telnet negotiation mode:", 't', 2,
1581 HELPCTX(telnet_passive),
1582 dlg_stdradiobutton_handler,
1583 I(offsetof(Config, passive_telnet)),
1584 "Passive", I(1), "Active", I(0), NULL);
1586 ctrl_checkbox(s, "Keyboard sends Telnet special commands", 'k',
1587 HELPCTX(telnet_specialkeys),
1588 dlg_stdcheckbox_handler,
1589 I(offsetof(Config,telnet_keyboard)));
1590 ctrl_checkbox(s, "Return key sends Telnet New Line instead of ^M",
1591 'm', HELPCTX(telnet_newline),
1592 dlg_stdcheckbox_handler,
1593 I(offsetof(Config,telnet_newline)));
1599 * The Connection/Rlogin panel.
1601 ctrl_settitle(b, "Connection/Rlogin",
1602 "Options controlling Rlogin connections");
1604 s = ctrl_getset(b, "Connection/Rlogin", "data",
1605 "Data to send to the server");
1606 ctrl_editbox(s, "Local username:", 'l', 50,
1607 HELPCTX(rlogin_localuser),
1608 dlg_stdeditbox_handler, I(offsetof(Config,localusername)),
1609 I(sizeof(((Config *)0)->localusername)));
1614 * All the SSH stuff is omitted in PuTTYtel, or in a reconfig
1615 * when we're not doing SSH.
1618 if (backends[3].name != NULL && (!midsession || protocol == PROT_SSH)) {
1621 * The Connection/SSH panel.
1623 ctrl_settitle(b, "Connection/SSH",
1624 "Options controlling SSH connections");
1626 if (midsession && protcfginfo == 1) {
1627 s = ctrl_getset(b, "Connection/SSH", "disclaimer", NULL);
1628 ctrl_text(s, "Nothing on this panel may be reconfigured in mid-"
1629 "session; it is only here so that sub-panels of it can "
1630 "exist without looking strange.", HELPCTX(no_help));
1635 s = ctrl_getset(b, "Connection/SSH", "data",
1636 "Data to send to the server");
1637 ctrl_editbox(s, "Remote command:", 'r', 100,
1638 HELPCTX(ssh_command),
1639 dlg_stdeditbox_handler, I(offsetof(Config,remote_cmd)),
1640 I(sizeof(((Config *)0)->remote_cmd)));
1642 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1643 ctrl_checkbox(s, "Don't allocate a pseudo-terminal", 'p',
1645 dlg_stdcheckbox_handler,
1646 I(offsetof(Config,nopty)));
1647 ctrl_checkbox(s, "Don't start a shell or command at all", 'n',
1648 HELPCTX(ssh_noshell),
1649 dlg_stdcheckbox_handler,
1650 I(offsetof(Config,ssh_no_shell)));
1653 if (!midsession || protcfginfo != 1) {
1654 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1656 ctrl_checkbox(s, "Enable compression", 'e',
1657 HELPCTX(ssh_compress),
1658 dlg_stdcheckbox_handler,
1659 I(offsetof(Config,compression)));
1663 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1665 ctrl_radiobuttons(s, "Preferred SSH protocol version:", NO_SHORTCUT, 4,
1666 HELPCTX(ssh_protocol),
1667 dlg_stdradiobutton_handler,
1668 I(offsetof(Config, sshprot)),
1669 "1 only", 'l', I(0),
1672 "2 only", 'y', I(3), NULL);
1675 if (!midsession || protcfginfo != 1) {
1676 s = ctrl_getset(b, "Connection/SSH", "encryption", "Encryption options");
1677 c = ctrl_draglist(s, "Encryption cipher selection policy:", 's',
1678 HELPCTX(ssh_ciphers),
1679 cipherlist_handler, P(NULL));
1680 c->listbox.height = 6;
1682 ctrl_checkbox(s, "Enable legacy use of single-DES in SSH-2", 'i',
1683 HELPCTX(ssh_ciphers),
1684 dlg_stdcheckbox_handler,
1685 I(offsetof(Config,ssh2_des_cbc)));
1689 * The Connection/SSH/Kex panel. (Owing to repeat key
1690 * exchange, this is all meaningful in mid-session _if_
1691 * we're using SSH-2 or haven't decided yet.)
1693 if (protcfginfo != 1) {
1694 ctrl_settitle(b, "Connection/SSH/Kex",
1695 "Options controlling SSH key exchange");
1697 s = ctrl_getset(b, "Connection/SSH/Kex", "main",
1698 "Key exchange algorithm options");
1699 c = ctrl_draglist(s, "Algorithm selection policy:", 's',
1700 HELPCTX(ssh_kexlist),
1701 kexlist_handler, P(NULL));
1702 c->listbox.height = 5;
1704 s = ctrl_getset(b, "Connection/SSH/Kex", "repeat",
1705 "Options controlling key re-exchange");
1707 ctrl_editbox(s, "Max minutes before rekey (0 for no limit)", 't', 20,
1708 HELPCTX(ssh_kex_repeat),
1709 dlg_stdeditbox_handler,
1710 I(offsetof(Config,ssh_rekey_time)),
1712 ctrl_editbox(s, "Max data before rekey (0 for no limit)", 'x', 20,
1713 HELPCTX(ssh_kex_repeat),
1714 dlg_stdeditbox_handler,
1715 I(offsetof(Config,ssh_rekey_data)),
1717 ctrl_text(s, "(Use 1M for 1 megabyte, 1G for 1 gigabyte etc)",
1718 HELPCTX(ssh_kex_repeat));
1724 * The Connection/SSH/Auth panel.
1726 ctrl_settitle(b, "Connection/SSH/Auth",
1727 "Options controlling SSH authentication");
1729 s = ctrl_getset(b, "Connection/SSH/Auth", "methods",
1730 "Authentication methods");
1731 ctrl_checkbox(s, "Attempt TIS or CryptoCard auth (SSH-1)", 'm',
1732 HELPCTX(ssh_auth_tis),
1733 dlg_stdcheckbox_handler,
1734 I(offsetof(Config,try_tis_auth)));
1735 ctrl_checkbox(s, "Attempt \"keyboard-interactive\" auth (SSH-2)",
1736 'i', HELPCTX(ssh_auth_ki),
1737 dlg_stdcheckbox_handler,
1738 I(offsetof(Config,try_ki_auth)));
1740 s = ctrl_getset(b, "Connection/SSH/Auth", "params",
1741 "Authentication parameters");
1742 ctrl_checkbox(s, "Allow agent forwarding", 'f',
1743 HELPCTX(ssh_auth_agentfwd),
1744 dlg_stdcheckbox_handler, I(offsetof(Config,agentfwd)));
1745 ctrl_checkbox(s, "Allow attempted changes of username in SSH-2", 'u',
1746 HELPCTX(ssh_auth_changeuser),
1747 dlg_stdcheckbox_handler,
1748 I(offsetof(Config,change_username)));
1749 ctrl_filesel(s, "Private key file for authentication:", 'k',
1750 FILTER_KEY_FILES, FALSE, "Select private key file",
1751 HELPCTX(ssh_auth_privkey),
1752 dlg_stdfilesel_handler, I(offsetof(Config, keyfile)));
1757 * The Connection/SSH/X11 panel.
1759 ctrl_settitle(b, "Connection/SSH/X11",
1760 "Options controlling SSH X11 forwarding");
1762 s = ctrl_getset(b, "Connection/SSH/X11", "x11", "X11 forwarding");
1763 ctrl_checkbox(s, "Enable X11 forwarding", 'e',
1764 HELPCTX(ssh_tunnels_x11),
1765 dlg_stdcheckbox_handler,I(offsetof(Config,x11_forward)));
1766 ctrl_editbox(s, "X display location", 'x', 50,
1767 HELPCTX(ssh_tunnels_x11),
1768 dlg_stdeditbox_handler, I(offsetof(Config,x11_display)),
1769 I(sizeof(((Config *)0)->x11_display)));
1770 ctrl_radiobuttons(s, "Remote X11 authentication protocol", 'u', 2,
1771 HELPCTX(ssh_tunnels_x11auth),
1772 dlg_stdradiobutton_handler,
1773 I(offsetof(Config, x11_auth)),
1774 "MIT-Magic-Cookie-1", I(X11_MIT),
1775 "XDM-Authorization-1", I(X11_XDM), NULL);
1779 * The Tunnels panel _is_ still available in mid-session.
1781 ctrl_settitle(b, "Connection/SSH/Tunnels",
1782 "Options controlling SSH port forwarding");
1784 s = ctrl_getset(b, "Connection/SSH/Tunnels", "portfwd",
1786 ctrl_checkbox(s, "Local ports accept connections from other hosts",'t',
1787 HELPCTX(ssh_tunnels_portfwd_localhost),
1788 dlg_stdcheckbox_handler,
1789 I(offsetof(Config,lport_acceptall)));
1790 ctrl_checkbox(s, "Remote ports do the same (SSH-2 only)", 'p',
1791 HELPCTX(ssh_tunnels_portfwd_localhost),
1792 dlg_stdcheckbox_handler,
1793 I(offsetof(Config,rport_acceptall)));
1795 ctrl_columns(s, 3, 55, 20, 25);
1796 c = ctrl_text(s, "Forwarded ports:", HELPCTX(ssh_tunnels_portfwd));
1797 c->generic.column = COLUMN_FIELD(0,2);
1798 /* You want to select from the list, _then_ hit Remove. So tab order
1799 * should be that way round. */
1800 pfd = (struct portfwd_data *)ctrl_alloc(b,sizeof(struct portfwd_data));
1801 pfd->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1802 HELPCTX(ssh_tunnels_portfwd),
1803 portfwd_handler, P(pfd));
1804 pfd->rembutton->generic.column = 2;
1805 pfd->rembutton->generic.tabdelay = 1;
1806 pfd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1807 HELPCTX(ssh_tunnels_portfwd),
1808 portfwd_handler, P(pfd));
1809 pfd->listbox->listbox.height = 3;
1810 pfd->listbox->listbox.ncols = 2;
1811 pfd->listbox->listbox.percentages = snewn(2, int);
1812 pfd->listbox->listbox.percentages[0] = 20;
1813 pfd->listbox->listbox.percentages[1] = 80;
1814 ctrl_tabdelay(s, pfd->rembutton);
1815 ctrl_text(s, "Add new forwarded port:", HELPCTX(ssh_tunnels_portfwd));
1816 /* You want to enter source, destination and type, _then_ hit Add.
1817 * Again, we adjust the tab order to reflect this. */
1818 pfd->addbutton = ctrl_pushbutton(s, "Add", 'd',
1819 HELPCTX(ssh_tunnels_portfwd),
1820 portfwd_handler, P(pfd));
1821 pfd->addbutton->generic.column = 2;
1822 pfd->addbutton->generic.tabdelay = 1;
1823 pfd->sourcebox = ctrl_editbox(s, "Source port", 's', 40,
1824 HELPCTX(ssh_tunnels_portfwd),
1825 portfwd_handler, P(pfd), P(NULL));
1826 pfd->sourcebox->generic.column = 0;
1827 pfd->destbox = ctrl_editbox(s, "Destination", 'i', 67,
1828 HELPCTX(ssh_tunnels_portfwd),
1829 portfwd_handler, P(pfd), P(NULL));
1830 pfd->direction = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
1831 HELPCTX(ssh_tunnels_portfwd),
1832 portfwd_handler, P(pfd),
1833 "Local", 'l', P(NULL),
1834 "Remote", 'm', P(NULL),
1835 "Dynamic", 'y', P(NULL),
1838 pfd->addressfamily =
1839 ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
1840 HELPCTX(ssh_tunnels_portfwd_ipversion),
1841 portfwd_handler, P(pfd),
1842 "Auto", NO_SHORTCUT, I(ADDRTYPE_UNSPEC),
1843 "IPv4", NO_SHORTCUT, I(ADDRTYPE_IPV4),
1844 "IPv6", NO_SHORTCUT, I(ADDRTYPE_IPV6),
1847 ctrl_tabdelay(s, pfd->addbutton);
1848 ctrl_columns(s, 1, 100);
1852 * The Connection/SSH/Bugs panel.
1854 ctrl_settitle(b, "Connection/SSH/Bugs",
1855 "Workarounds for SSH server bugs");
1857 s = ctrl_getset(b, "Connection/SSH/Bugs", "main",
1858 "Detection of known bugs in SSH servers");
1859 ctrl_droplist(s, "Chokes on SSH-1 ignore messages", 'i', 20,
1860 HELPCTX(ssh_bugs_ignore1),
1861 sshbug_handler, I(offsetof(Config,sshbug_ignore1)));
1862 ctrl_droplist(s, "Refuses all SSH-1 password camouflage", 's', 20,
1863 HELPCTX(ssh_bugs_plainpw1),
1864 sshbug_handler, I(offsetof(Config,sshbug_plainpw1)));
1865 ctrl_droplist(s, "Chokes on SSH-1 RSA authentication", 'r', 20,
1866 HELPCTX(ssh_bugs_rsa1),
1867 sshbug_handler, I(offsetof(Config,sshbug_rsa1)));
1868 ctrl_droplist(s, "Miscomputes SSH-2 HMAC keys", 'm', 20,
1869 HELPCTX(ssh_bugs_hmac2),
1870 sshbug_handler, I(offsetof(Config,sshbug_hmac2)));
1871 ctrl_droplist(s, "Miscomputes SSH-2 encryption keys", 'e', 20,
1872 HELPCTX(ssh_bugs_derivekey2),
1873 sshbug_handler, I(offsetof(Config,sshbug_derivekey2)));
1874 ctrl_droplist(s, "Requires padding on SSH-2 RSA signatures", 'p', 20,
1875 HELPCTX(ssh_bugs_rsapad2),
1876 sshbug_handler, I(offsetof(Config,sshbug_rsapad2)));
1877 ctrl_droplist(s, "Misuses the session ID in SSH-2 PK auth", 'n', 20,
1878 HELPCTX(ssh_bugs_pksessid2),
1879 sshbug_handler, I(offsetof(Config,sshbug_pksessid2)));
1880 ctrl_droplist(s, "Handles SSH-2 key re-exchange badly", 'k', 20,
1881 HELPCTX(ssh_bugs_rekey2),
1882 sshbug_handler, I(offsetof(Config,sshbug_rekey2)));