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