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 str = dupprintf("Adjust how %s handles line drawing characters", appname);
1286 s = ctrl_getset(b, "Window/Translation", "linedraw", str);
1288 ctrl_radiobuttons(s, "Handling of line drawing characters:", NO_SHORTCUT,1,
1289 HELPCTX(translation_linedraw),
1290 dlg_stdradiobutton_handler,
1291 I(offsetof(Config, vtmode)),
1292 "Use Unicode line drawing code points",'u',I(VT_UNICODE),
1293 "Poor man's line drawing (+, - and |)",'p',I(VT_POORMAN),
1295 ctrl_checkbox(s, "Copy and paste line drawing characters as lqqqk",'d',
1296 HELPCTX(selection_linedraw),
1297 dlg_stdcheckbox_handler, I(offsetof(Config,rawcnp)));
1300 * The Window/Selection panel.
1302 ctrl_settitle(b, "Window/Selection", "Options controlling copy and paste");
1304 s = ctrl_getset(b, "Window/Selection", "mouse",
1305 "Control use of mouse");
1306 ctrl_checkbox(s, "Shift overrides application's use of mouse", 'p',
1307 HELPCTX(selection_shiftdrag),
1308 dlg_stdcheckbox_handler, I(offsetof(Config,mouse_override)));
1309 ctrl_radiobuttons(s,
1310 "Default selection mode (Alt+drag does the other one):",
1312 HELPCTX(selection_rect),
1313 dlg_stdradiobutton_handler,
1314 I(offsetof(Config, rect_select)),
1315 "Normal", 'n', I(0),
1316 "Rectangular block", 'r', I(1), NULL);
1318 s = ctrl_getset(b, "Window/Selection", "charclass",
1319 "Control the select-one-word-at-a-time mode");
1320 ccd = (struct charclass_data *)
1321 ctrl_alloc(b, sizeof(struct charclass_data));
1322 ccd->listbox = ctrl_listbox(s, "Character classes:", 'e',
1323 HELPCTX(selection_charclasses),
1324 charclass_handler, P(ccd));
1325 ccd->listbox->listbox.multisel = 1;
1326 ccd->listbox->listbox.ncols = 4;
1327 ccd->listbox->listbox.percentages = snewn(4, int);
1328 ccd->listbox->listbox.percentages[0] = 15;
1329 ccd->listbox->listbox.percentages[1] = 25;
1330 ccd->listbox->listbox.percentages[2] = 20;
1331 ccd->listbox->listbox.percentages[3] = 40;
1332 ctrl_columns(s, 2, 67, 33);
1333 ccd->editbox = ctrl_editbox(s, "Set to class", 't', 50,
1334 HELPCTX(selection_charclasses),
1335 charclass_handler, P(ccd), P(NULL));
1336 ccd->editbox->generic.column = 0;
1337 ccd->button = ctrl_pushbutton(s, "Set", 's',
1338 HELPCTX(selection_charclasses),
1339 charclass_handler, P(ccd));
1340 ccd->button->generic.column = 1;
1341 ctrl_columns(s, 1, 100);
1344 * The Window/Colours panel.
1346 ctrl_settitle(b, "Window/Colours", "Options controlling use of colours");
1348 s = ctrl_getset(b, "Window/Colours", "general",
1349 "General options for colour usage");
1350 ctrl_checkbox(s, "Allow terminal to specify ANSI colours", 'i',
1351 HELPCTX(colours_ansi),
1352 dlg_stdcheckbox_handler, I(offsetof(Config,ansi_colour)));
1353 ctrl_checkbox(s, "Allow terminal to use xterm 256-colour mode", '2',
1354 HELPCTX(colours_xterm256), dlg_stdcheckbox_handler,
1355 I(offsetof(Config,xterm_256_colour)));
1356 ctrl_checkbox(s, "Bolded text is a different colour", 'b',
1357 HELPCTX(colours_bold),
1358 dlg_stdcheckbox_handler, I(offsetof(Config,bold_colour)));
1360 str = dupprintf("Adjust the precise colours %s displays", appname);
1361 s = ctrl_getset(b, "Window/Colours", "adjust", str);
1363 ctrl_text(s, "Select a colour from the list, and then click the"
1364 " Modify button to change its appearance.",
1365 HELPCTX(colours_config));
1366 ctrl_columns(s, 2, 67, 33);
1367 cd = (struct colour_data *)ctrl_alloc(b, sizeof(struct colour_data));
1368 cd->listbox = ctrl_listbox(s, "Select a colour to adjust:", 'u',
1369 HELPCTX(colours_config), colour_handler, P(cd));
1370 cd->listbox->generic.column = 0;
1371 cd->listbox->listbox.height = 7;
1372 c = ctrl_text(s, "RGB value:", HELPCTX(colours_config));
1373 c->generic.column = 1;
1374 cd->redit = ctrl_editbox(s, "Red", 'r', 50, HELPCTX(colours_config),
1375 colour_handler, P(cd), P(NULL));
1376 cd->redit->generic.column = 1;
1377 cd->gedit = ctrl_editbox(s, "Green", 'n', 50, HELPCTX(colours_config),
1378 colour_handler, P(cd), P(NULL));
1379 cd->gedit->generic.column = 1;
1380 cd->bedit = ctrl_editbox(s, "Blue", 'e', 50, HELPCTX(colours_config),
1381 colour_handler, P(cd), P(NULL));
1382 cd->bedit->generic.column = 1;
1383 cd->button = ctrl_pushbutton(s, "Modify", 'm', HELPCTX(colours_config),
1384 colour_handler, P(cd));
1385 cd->button->generic.column = 1;
1386 ctrl_columns(s, 1, 100);
1389 * The Connection panel. This doesn't show up if we're in a
1390 * non-network utility such as pterm. We tell this by being
1391 * passed a protocol < 0.
1393 if (protocol >= 0) {
1394 ctrl_settitle(b, "Connection", "Options controlling the connection");
1396 s = ctrl_getset(b, "Connection", "keepalive",
1397 "Sending of null packets to keep session active");
1398 ctrl_editbox(s, "Seconds between keepalives (0 to turn off)", 'k', 20,
1399 HELPCTX(connection_keepalive),
1400 dlg_stdeditbox_handler, I(offsetof(Config,ping_interval)),
1404 s = ctrl_getset(b, "Connection", "tcp",
1405 "Low-level TCP connection options");
1406 ctrl_checkbox(s, "Disable Nagle's algorithm (TCP_NODELAY option)",
1407 'n', HELPCTX(connection_nodelay),
1408 dlg_stdcheckbox_handler,
1409 I(offsetof(Config,tcp_nodelay)));
1410 ctrl_checkbox(s, "Enable TCP keepalives (SO_KEEPALIVE option)",
1411 'p', HELPCTX(connection_tcpkeepalive),
1412 dlg_stdcheckbox_handler,
1413 I(offsetof(Config,tcp_keepalives)));
1415 s = ctrl_getset(b, "Connection", "ipversion",
1416 "Internet protocol version");
1417 ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
1418 HELPCTX(connection_ipversion),
1419 dlg_stdradiobutton_handler,
1420 I(offsetof(Config, addressfamily)),
1421 "Auto", NO_SHORTCUT, I(ADDRTYPE_UNSPEC),
1422 "IPv4", NO_SHORTCUT, I(ADDRTYPE_IPV4),
1423 "IPv6", NO_SHORTCUT, I(ADDRTYPE_IPV6),
1429 * A sub-panel Connection/Data, containing options that
1430 * decide on data to send to the server.
1433 ctrl_settitle(b, "Connection/Data", "Data to send to the server");
1435 s = ctrl_getset(b, "Connection/Data", "login",
1437 ctrl_editbox(s, "Auto-login username", 'u', 50,
1438 HELPCTX(connection_username),
1439 dlg_stdeditbox_handler, I(offsetof(Config,username)),
1440 I(sizeof(((Config *)0)->username)));
1442 s = ctrl_getset(b, "Connection/Data", "term",
1443 "Terminal details");
1444 ctrl_editbox(s, "Terminal-type string", 't', 50,
1445 HELPCTX(connection_termtype),
1446 dlg_stdeditbox_handler, I(offsetof(Config,termtype)),
1447 I(sizeof(((Config *)0)->termtype)));
1448 ctrl_editbox(s, "Terminal speeds", 's', 50,
1449 HELPCTX(connection_termspeed),
1450 dlg_stdeditbox_handler, I(offsetof(Config,termspeed)),
1451 I(sizeof(((Config *)0)->termspeed)));
1453 s = ctrl_getset(b, "Connection/Data", "env",
1454 "Environment variables");
1455 ctrl_columns(s, 2, 80, 20);
1456 ed = (struct environ_data *)
1457 ctrl_alloc(b, sizeof(struct environ_data));
1458 ed->varbox = ctrl_editbox(s, "Variable", 'v', 60,
1459 HELPCTX(telnet_environ),
1460 environ_handler, P(ed), P(NULL));
1461 ed->varbox->generic.column = 0;
1462 ed->valbox = ctrl_editbox(s, "Value", 'l', 60,
1463 HELPCTX(telnet_environ),
1464 environ_handler, P(ed), P(NULL));
1465 ed->valbox->generic.column = 0;
1466 ed->addbutton = ctrl_pushbutton(s, "Add", 'd',
1467 HELPCTX(telnet_environ),
1468 environ_handler, P(ed));
1469 ed->addbutton->generic.column = 1;
1470 ed->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1471 HELPCTX(telnet_environ),
1472 environ_handler, P(ed));
1473 ed->rembutton->generic.column = 1;
1474 ctrl_columns(s, 1, 100);
1475 ed->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1476 HELPCTX(telnet_environ),
1477 environ_handler, P(ed));
1478 ed->listbox->listbox.height = 3;
1479 ed->listbox->listbox.ncols = 2;
1480 ed->listbox->listbox.percentages = snewn(2, int);
1481 ed->listbox->listbox.percentages[0] = 30;
1482 ed->listbox->listbox.percentages[1] = 70;
1489 * The Connection/Proxy panel.
1491 ctrl_settitle(b, "Connection/Proxy",
1492 "Options controlling proxy usage");
1494 s = ctrl_getset(b, "Connection/Proxy", "basics", NULL);
1495 ctrl_radiobuttons(s, "Proxy type:", 't', 3,
1496 HELPCTX(proxy_type),
1497 dlg_stdradiobutton_handler,
1498 I(offsetof(Config, proxy_type)),
1499 "None", I(PROXY_NONE),
1500 "SOCKS 4", I(PROXY_SOCKS4),
1501 "SOCKS 5", I(PROXY_SOCKS5),
1502 "HTTP", I(PROXY_HTTP),
1503 "Telnet", I(PROXY_TELNET),
1505 ctrl_columns(s, 2, 80, 20);
1506 c = ctrl_editbox(s, "Proxy hostname", 'y', 100,
1507 HELPCTX(proxy_main),
1508 dlg_stdeditbox_handler,
1509 I(offsetof(Config,proxy_host)),
1510 I(sizeof(((Config *)0)->proxy_host)));
1511 c->generic.column = 0;
1512 c = ctrl_editbox(s, "Port", 'p', 100,
1513 HELPCTX(proxy_main),
1514 dlg_stdeditbox_handler,
1515 I(offsetof(Config,proxy_port)),
1517 c->generic.column = 1;
1518 ctrl_columns(s, 1, 100);
1519 ctrl_editbox(s, "Exclude Hosts/IPs", 'e', 100,
1520 HELPCTX(proxy_exclude),
1521 dlg_stdeditbox_handler,
1522 I(offsetof(Config,proxy_exclude_list)),
1523 I(sizeof(((Config *)0)->proxy_exclude_list)));
1524 ctrl_checkbox(s, "Consider proxying local host connections", 'x',
1525 HELPCTX(proxy_exclude),
1526 dlg_stdcheckbox_handler,
1527 I(offsetof(Config,even_proxy_localhost)));
1528 ctrl_radiobuttons(s, "Do DNS name lookup at proxy end:", 'd', 3,
1530 dlg_stdradiobutton_handler,
1531 I(offsetof(Config, proxy_dns)),
1534 "Yes", I(FORCE_ON), NULL);
1535 ctrl_editbox(s, "Username", 'u', 60,
1536 HELPCTX(proxy_auth),
1537 dlg_stdeditbox_handler,
1538 I(offsetof(Config,proxy_username)),
1539 I(sizeof(((Config *)0)->proxy_username)));
1540 c = ctrl_editbox(s, "Password", 'w', 60,
1541 HELPCTX(proxy_auth),
1542 dlg_stdeditbox_handler,
1543 I(offsetof(Config,proxy_password)),
1544 I(sizeof(((Config *)0)->proxy_password)));
1545 c->editbox.password = 1;
1546 ctrl_editbox(s, "Telnet command", 'm', 100,
1547 HELPCTX(proxy_command),
1548 dlg_stdeditbox_handler,
1549 I(offsetof(Config,proxy_telnet_command)),
1550 I(sizeof(((Config *)0)->proxy_telnet_command)));
1554 * The Telnet panel exists in the base config box, and in a
1555 * mid-session reconfig box _if_ we're using Telnet.
1557 if (!midsession || protocol == PROT_TELNET) {
1559 * The Connection/Telnet panel.
1561 ctrl_settitle(b, "Connection/Telnet",
1562 "Options controlling Telnet connections");
1564 s = ctrl_getset(b, "Connection/Telnet", "protocol",
1565 "Telnet protocol adjustments");
1568 ctrl_radiobuttons(s, "Handling of OLD_ENVIRON ambiguity:",
1570 HELPCTX(telnet_oldenviron),
1571 dlg_stdradiobutton_handler,
1572 I(offsetof(Config, rfc_environ)),
1573 "BSD (commonplace)", 'b', I(0),
1574 "RFC 1408 (unusual)", 'f', I(1), NULL);
1575 ctrl_radiobuttons(s, "Telnet negotiation mode:", 't', 2,
1576 HELPCTX(telnet_passive),
1577 dlg_stdradiobutton_handler,
1578 I(offsetof(Config, passive_telnet)),
1579 "Passive", I(1), "Active", I(0), NULL);
1581 ctrl_checkbox(s, "Keyboard sends Telnet special commands", 'k',
1582 HELPCTX(telnet_specialkeys),
1583 dlg_stdcheckbox_handler,
1584 I(offsetof(Config,telnet_keyboard)));
1585 ctrl_checkbox(s, "Return key sends Telnet New Line instead of ^M",
1586 'm', HELPCTX(telnet_newline),
1587 dlg_stdcheckbox_handler,
1588 I(offsetof(Config,telnet_newline)));
1594 * The Connection/Rlogin panel.
1596 ctrl_settitle(b, "Connection/Rlogin",
1597 "Options controlling Rlogin connections");
1599 s = ctrl_getset(b, "Connection/Rlogin", "data",
1600 "Data to send to the server");
1601 ctrl_editbox(s, "Local username:", 'l', 50,
1602 HELPCTX(rlogin_localuser),
1603 dlg_stdeditbox_handler, I(offsetof(Config,localusername)),
1604 I(sizeof(((Config *)0)->localusername)));
1609 * All the SSH stuff is omitted in PuTTYtel, or in a reconfig
1610 * when we're not doing SSH.
1613 if (backends[3].name != NULL && (!midsession || protocol == PROT_SSH)) {
1616 * The Connection/SSH panel.
1618 ctrl_settitle(b, "Connection/SSH",
1619 "Options controlling SSH connections");
1621 if (midsession && protcfginfo == 1) {
1622 s = ctrl_getset(b, "Connection/SSH", "disclaimer", NULL);
1623 ctrl_text(s, "Nothing on this panel may be reconfigured in mid-"
1624 "session; it is only here so that sub-panels of it can "
1625 "exist without looking strange.", HELPCTX(no_help));
1630 s = ctrl_getset(b, "Connection/SSH", "data",
1631 "Data to send to the server");
1632 ctrl_editbox(s, "Remote command:", 'r', 100,
1633 HELPCTX(ssh_command),
1634 dlg_stdeditbox_handler, I(offsetof(Config,remote_cmd)),
1635 I(sizeof(((Config *)0)->remote_cmd)));
1637 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1638 ctrl_checkbox(s, "Don't allocate a pseudo-terminal", 'p',
1640 dlg_stdcheckbox_handler,
1641 I(offsetof(Config,nopty)));
1642 ctrl_checkbox(s, "Don't start a shell or command at all", 'n',
1643 HELPCTX(ssh_noshell),
1644 dlg_stdcheckbox_handler,
1645 I(offsetof(Config,ssh_no_shell)));
1648 if (!midsession || protcfginfo != 1) {
1649 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1651 ctrl_checkbox(s, "Enable compression", 'e',
1652 HELPCTX(ssh_compress),
1653 dlg_stdcheckbox_handler,
1654 I(offsetof(Config,compression)));
1658 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1660 ctrl_radiobuttons(s, "Preferred SSH protocol version:", NO_SHORTCUT, 4,
1661 HELPCTX(ssh_protocol),
1662 dlg_stdradiobutton_handler,
1663 I(offsetof(Config, sshprot)),
1664 "1 only", 'l', I(0),
1667 "2 only", 'y', I(3), NULL);
1670 if (!midsession || protcfginfo != 1) {
1671 s = ctrl_getset(b, "Connection/SSH", "encryption", "Encryption options");
1672 c = ctrl_draglist(s, "Encryption cipher selection policy:", 's',
1673 HELPCTX(ssh_ciphers),
1674 cipherlist_handler, P(NULL));
1675 c->listbox.height = 6;
1677 ctrl_checkbox(s, "Enable legacy use of single-DES in SSH-2", 'i',
1678 HELPCTX(ssh_ciphers),
1679 dlg_stdcheckbox_handler,
1680 I(offsetof(Config,ssh2_des_cbc)));
1684 * The Connection/SSH/Kex panel. (Owing to repeat key
1685 * exchange, this is all meaningful in mid-session _if_
1686 * we're using SSH-2 or haven't decided yet.)
1688 if (protcfginfo != 1) {
1689 ctrl_settitle(b, "Connection/SSH/Kex",
1690 "Options controlling SSH key exchange");
1692 s = ctrl_getset(b, "Connection/SSH/Kex", "main",
1693 "Key exchange algorithm options");
1694 c = ctrl_draglist(s, "Algorithm selection policy:", 's',
1695 HELPCTX(ssh_kexlist),
1696 kexlist_handler, P(NULL));
1697 c->listbox.height = 5;
1699 s = ctrl_getset(b, "Connection/SSH/Kex", "repeat",
1700 "Options controlling key re-exchange");
1702 ctrl_editbox(s, "Max minutes before rekey (0 for no limit)", 't', 20,
1703 HELPCTX(ssh_kex_repeat),
1704 dlg_stdeditbox_handler,
1705 I(offsetof(Config,ssh_rekey_time)),
1707 ctrl_editbox(s, "Max data before rekey (0 for no limit)", 'x', 20,
1708 HELPCTX(ssh_kex_repeat),
1709 dlg_stdeditbox_handler,
1710 I(offsetof(Config,ssh_rekey_data)),
1712 ctrl_text(s, "(Use 1M for 1 megabyte, 1G for 1 gigabyte etc)",
1713 HELPCTX(ssh_kex_repeat));
1719 * The Connection/SSH/Auth panel.
1721 ctrl_settitle(b, "Connection/SSH/Auth",
1722 "Options controlling SSH authentication");
1724 s = ctrl_getset(b, "Connection/SSH/Auth", "methods",
1725 "Authentication methods");
1726 ctrl_checkbox(s, "Attempt TIS or CryptoCard auth (SSH-1)", 'm',
1727 HELPCTX(ssh_auth_tis),
1728 dlg_stdcheckbox_handler,
1729 I(offsetof(Config,try_tis_auth)));
1730 ctrl_checkbox(s, "Attempt \"keyboard-interactive\" auth (SSH-2)",
1731 'i', HELPCTX(ssh_auth_ki),
1732 dlg_stdcheckbox_handler,
1733 I(offsetof(Config,try_ki_auth)));
1735 s = ctrl_getset(b, "Connection/SSH/Auth", "params",
1736 "Authentication parameters");
1737 ctrl_checkbox(s, "Allow agent forwarding", 'f',
1738 HELPCTX(ssh_auth_agentfwd),
1739 dlg_stdcheckbox_handler, I(offsetof(Config,agentfwd)));
1740 ctrl_checkbox(s, "Allow attempted changes of username in SSH-2", 'u',
1741 HELPCTX(ssh_auth_changeuser),
1742 dlg_stdcheckbox_handler,
1743 I(offsetof(Config,change_username)));
1744 ctrl_filesel(s, "Private key file for authentication:", 'k',
1745 FILTER_KEY_FILES, FALSE, "Select private key file",
1746 HELPCTX(ssh_auth_privkey),
1747 dlg_stdfilesel_handler, I(offsetof(Config, keyfile)));
1752 * The Connection/SSH/X11 panel.
1754 ctrl_settitle(b, "Connection/SSH/X11",
1755 "Options controlling SSH X11 forwarding");
1757 s = ctrl_getset(b, "Connection/SSH/X11", "x11", "X11 forwarding");
1758 ctrl_checkbox(s, "Enable X11 forwarding", 'e',
1759 HELPCTX(ssh_tunnels_x11),
1760 dlg_stdcheckbox_handler,I(offsetof(Config,x11_forward)));
1761 ctrl_editbox(s, "X display location", 'x', 50,
1762 HELPCTX(ssh_tunnels_x11),
1763 dlg_stdeditbox_handler, I(offsetof(Config,x11_display)),
1764 I(sizeof(((Config *)0)->x11_display)));
1765 ctrl_radiobuttons(s, "Remote X11 authentication protocol", 'u', 2,
1766 HELPCTX(ssh_tunnels_x11auth),
1767 dlg_stdradiobutton_handler,
1768 I(offsetof(Config, x11_auth)),
1769 "MIT-Magic-Cookie-1", I(X11_MIT),
1770 "XDM-Authorization-1", I(X11_XDM), NULL);
1774 * The Tunnels panel _is_ still available in mid-session.
1776 ctrl_settitle(b, "Connection/SSH/Tunnels",
1777 "Options controlling SSH port forwarding");
1779 s = ctrl_getset(b, "Connection/SSH/Tunnels", "portfwd",
1781 ctrl_checkbox(s, "Local ports accept connections from other hosts",'t',
1782 HELPCTX(ssh_tunnels_portfwd_localhost),
1783 dlg_stdcheckbox_handler,
1784 I(offsetof(Config,lport_acceptall)));
1785 ctrl_checkbox(s, "Remote ports do the same (SSH-2 only)", 'p',
1786 HELPCTX(ssh_tunnels_portfwd_localhost),
1787 dlg_stdcheckbox_handler,
1788 I(offsetof(Config,rport_acceptall)));
1790 ctrl_columns(s, 3, 55, 20, 25);
1791 c = ctrl_text(s, "Forwarded ports:", HELPCTX(ssh_tunnels_portfwd));
1792 c->generic.column = COLUMN_FIELD(0,2);
1793 /* You want to select from the list, _then_ hit Remove. So tab order
1794 * should be that way round. */
1795 pfd = (struct portfwd_data *)ctrl_alloc(b,sizeof(struct portfwd_data));
1796 pfd->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1797 HELPCTX(ssh_tunnels_portfwd),
1798 portfwd_handler, P(pfd));
1799 pfd->rembutton->generic.column = 2;
1800 pfd->rembutton->generic.tabdelay = 1;
1801 pfd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1802 HELPCTX(ssh_tunnels_portfwd),
1803 portfwd_handler, P(pfd));
1804 pfd->listbox->listbox.height = 3;
1805 pfd->listbox->listbox.ncols = 2;
1806 pfd->listbox->listbox.percentages = snewn(2, int);
1807 pfd->listbox->listbox.percentages[0] = 20;
1808 pfd->listbox->listbox.percentages[1] = 80;
1809 ctrl_tabdelay(s, pfd->rembutton);
1810 ctrl_text(s, "Add new forwarded port:", HELPCTX(ssh_tunnels_portfwd));
1811 /* You want to enter source, destination and type, _then_ hit Add.
1812 * Again, we adjust the tab order to reflect this. */
1813 pfd->addbutton = ctrl_pushbutton(s, "Add", 'd',
1814 HELPCTX(ssh_tunnels_portfwd),
1815 portfwd_handler, P(pfd));
1816 pfd->addbutton->generic.column = 2;
1817 pfd->addbutton->generic.tabdelay = 1;
1818 pfd->sourcebox = ctrl_editbox(s, "Source port", 's', 40,
1819 HELPCTX(ssh_tunnels_portfwd),
1820 portfwd_handler, P(pfd), P(NULL));
1821 pfd->sourcebox->generic.column = 0;
1822 pfd->destbox = ctrl_editbox(s, "Destination", 'i', 67,
1823 HELPCTX(ssh_tunnels_portfwd),
1824 portfwd_handler, P(pfd), P(NULL));
1825 pfd->direction = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
1826 HELPCTX(ssh_tunnels_portfwd),
1827 portfwd_handler, P(pfd),
1828 "Local", 'l', P(NULL),
1829 "Remote", 'm', P(NULL),
1830 "Dynamic", 'y', P(NULL),
1833 pfd->addressfamily =
1834 ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
1835 HELPCTX(ssh_tunnels_portfwd_ipversion),
1836 portfwd_handler, P(pfd),
1837 "Auto", NO_SHORTCUT, I(ADDRTYPE_UNSPEC),
1838 "IPv4", NO_SHORTCUT, I(ADDRTYPE_IPV4),
1839 "IPv6", NO_SHORTCUT, I(ADDRTYPE_IPV6),
1842 ctrl_tabdelay(s, pfd->addbutton);
1843 ctrl_columns(s, 1, 100);
1847 * The Connection/SSH/Bugs panel.
1849 ctrl_settitle(b, "Connection/SSH/Bugs",
1850 "Workarounds for SSH server bugs");
1852 s = ctrl_getset(b, "Connection/SSH/Bugs", "main",
1853 "Detection of known bugs in SSH servers");
1854 ctrl_droplist(s, "Chokes on SSH-1 ignore messages", 'i', 20,
1855 HELPCTX(ssh_bugs_ignore1),
1856 sshbug_handler, I(offsetof(Config,sshbug_ignore1)));
1857 ctrl_droplist(s, "Refuses all SSH-1 password camouflage", 's', 20,
1858 HELPCTX(ssh_bugs_plainpw1),
1859 sshbug_handler, I(offsetof(Config,sshbug_plainpw1)));
1860 ctrl_droplist(s, "Chokes on SSH-1 RSA authentication", 'r', 20,
1861 HELPCTX(ssh_bugs_rsa1),
1862 sshbug_handler, I(offsetof(Config,sshbug_rsa1)));
1863 ctrl_droplist(s, "Miscomputes SSH-2 HMAC keys", 'm', 20,
1864 HELPCTX(ssh_bugs_hmac2),
1865 sshbug_handler, I(offsetof(Config,sshbug_hmac2)));
1866 ctrl_droplist(s, "Miscomputes SSH-2 encryption keys", 'e', 20,
1867 HELPCTX(ssh_bugs_derivekey2),
1868 sshbug_handler, I(offsetof(Config,sshbug_derivekey2)));
1869 ctrl_droplist(s, "Requires padding on SSH-2 RSA signatures", 'p', 20,
1870 HELPCTX(ssh_bugs_rsapad2),
1871 sshbug_handler, I(offsetof(Config,sshbug_rsapad2)));
1872 ctrl_droplist(s, "Misuses the session ID in SSH-2 PK auth", 'n', 20,
1873 HELPCTX(ssh_bugs_pksessid2),
1874 sshbug_handler, I(offsetof(Config,sshbug_pksessid2)));
1875 ctrl_droplist(s, "Handles SSH-2 key re-exchange badly", 'k', 20,
1876 HELPCTX(ssh_bugs_rekey2),
1877 sshbug_handler, I(offsetof(Config,sshbug_rekey2)));