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 printerbox_handler(union control *ctrl, void *dlg,
128 void *data, int event)
130 Config *cfg = (Config *)data;
131 if (event == EVENT_REFRESH) {
135 dlg_update_start(ctrl, dlg);
137 * Some backends may wish to disable the drop-down list on
138 * this edit box. Be prepared for this.
140 if (ctrl->editbox.has_list) {
141 dlg_listbox_clear(ctrl, dlg);
142 dlg_listbox_add(ctrl, dlg, PRINTER_DISABLED_STRING);
143 pe = printer_start_enum(&nprinters);
144 for (i = 0; i < nprinters; i++)
145 dlg_listbox_add(ctrl, dlg, printer_get_name(pe, i));
146 printer_finish_enum(pe);
148 dlg_editbox_set(ctrl, dlg,
149 (*cfg->printer ? cfg->printer :
150 PRINTER_DISABLED_STRING));
151 dlg_update_done(ctrl, dlg);
152 } else if (event == EVENT_VALCHANGE) {
153 dlg_editbox_get(ctrl, dlg, cfg->printer, sizeof(cfg->printer));
154 if (!strcmp(cfg->printer, PRINTER_DISABLED_STRING))
155 *cfg->printer = '\0';
159 static void codepage_handler(union control *ctrl, void *dlg,
160 void *data, int event)
162 Config *cfg = (Config *)data;
163 if (event == EVENT_REFRESH) {
166 dlg_update_start(ctrl, dlg);
167 strcpy(cfg->line_codepage,
168 cp_name(decode_codepage(cfg->line_codepage)));
169 dlg_listbox_clear(ctrl, dlg);
170 for (i = 0; (cp = cp_enumerate(i)) != NULL; i++)
171 dlg_listbox_add(ctrl, dlg, cp);
172 dlg_editbox_set(ctrl, dlg, cfg->line_codepage);
173 dlg_update_done(ctrl, dlg);
174 } else if (event == EVENT_VALCHANGE) {
175 dlg_editbox_get(ctrl, dlg, cfg->line_codepage,
176 sizeof(cfg->line_codepage));
177 strcpy(cfg->line_codepage,
178 cp_name(decode_codepage(cfg->line_codepage)));
182 static void sshbug_handler(union control *ctrl, void *dlg,
183 void *data, int event)
185 if (event == EVENT_REFRESH) {
186 dlg_update_start(ctrl, dlg);
187 dlg_listbox_clear(ctrl, dlg);
188 dlg_listbox_addwithid(ctrl, dlg, "Auto", AUTO);
189 dlg_listbox_addwithid(ctrl, dlg, "Off", FORCE_OFF);
190 dlg_listbox_addwithid(ctrl, dlg, "On", FORCE_ON);
191 switch (*(int *)ATOFFSET(data, ctrl->listbox.context.i)) {
192 case AUTO: dlg_listbox_select(ctrl, dlg, 0); break;
193 case FORCE_OFF: dlg_listbox_select(ctrl, dlg, 1); break;
194 case FORCE_ON: dlg_listbox_select(ctrl, dlg, 2); break;
196 dlg_update_done(ctrl, dlg);
197 } else if (event == EVENT_SELCHANGE) {
198 int i = dlg_listbox_index(ctrl, dlg);
202 i = dlg_listbox_getid(ctrl, dlg, i);
203 *(int *)ATOFFSET(data, ctrl->listbox.context.i) = i;
207 #define SAVEDSESSION_LEN 2048
209 struct sessionsaver_data {
210 union control *editbox, *listbox, *loadbutton, *savebutton, *delbutton;
211 union control *okbutton, *cancelbutton;
212 struct sesslist *sesslist;
216 * Helper function to load the session selected in the list box, if
217 * any, as this is done in more than one place below. Returns 0 for
220 static int load_selected_session(struct sessionsaver_data *ssd,
222 void *dlg, Config *cfg)
224 int i = dlg_listbox_index(ssd->listbox, dlg);
230 isdef = !strcmp(ssd->sesslist->sessions[i], "Default Settings");
231 load_settings(ssd->sesslist->sessions[i], !isdef, cfg);
233 strncpy(savedsession, ssd->sesslist->sessions[i],
235 savedsession[SAVEDSESSION_LEN-1] = '\0';
237 savedsession[0] = '\0';
239 dlg_refresh(NULL, dlg);
240 /* Restore the selection, which might have been clobbered by
241 * changing the value of the edit box. */
242 dlg_listbox_select(ssd->listbox, dlg, i);
246 static void sessionsaver_handler(union control *ctrl, void *dlg,
247 void *data, int event)
249 Config *cfg = (Config *)data;
250 struct sessionsaver_data *ssd =
251 (struct sessionsaver_data *)ctrl->generic.context.p;
255 * The first time we're called in a new dialog, we must
256 * allocate space to store the current contents of the saved
257 * session edit box (since it must persist even when we switch
258 * panels, but is not part of the Config).
260 * Of course, this doesn't need to be done mid-session.
264 } else if (!dlg_get_privdata(ssd->editbox, dlg)) {
265 savedsession = (char *)
266 dlg_alloc_privdata(ssd->editbox, dlg, SAVEDSESSION_LEN);
267 savedsession[0] = '\0';
269 savedsession = dlg_get_privdata(ssd->editbox, dlg);
272 if (event == EVENT_REFRESH) {
273 if (ctrl == ssd->editbox) {
274 dlg_editbox_set(ctrl, dlg, savedsession);
275 } else if (ctrl == ssd->listbox) {
277 dlg_update_start(ctrl, dlg);
278 dlg_listbox_clear(ctrl, dlg);
279 for (i = 0; i < ssd->sesslist->nsessions; i++)
280 dlg_listbox_add(ctrl, dlg, ssd->sesslist->sessions[i]);
281 dlg_update_done(ctrl, dlg);
283 } else if (event == EVENT_VALCHANGE) {
284 if (ctrl == ssd->editbox) {
285 dlg_editbox_get(ctrl, dlg, savedsession,
288 } else if (event == EVENT_ACTION) {
289 if (ctrl == ssd->listbox || ctrl == ssd->loadbutton) {
291 * The user has double-clicked a session, or hit Load.
292 * We must load the selected session, and then
293 * terminate the configuration dialog _if_ there was a
294 * double-click on the list box _and_ that session
295 * contains a hostname.
297 if (load_selected_session(ssd, savedsession, dlg, cfg) &&
298 (ctrl == ssd->listbox && cfg->host[0])) {
299 dlg_end(dlg, 1); /* it's all over, and succeeded */
301 } else if (ctrl == ssd->savebutton) {
302 int isdef = !strcmp(savedsession, "Default Settings");
303 if (!savedsession[0]) {
304 int i = dlg_listbox_index(ssd->listbox, dlg);
309 isdef = !strcmp(ssd->sesslist->sessions[i], "Default Settings");
311 strncpy(savedsession, ssd->sesslist->sessions[i],
313 savedsession[SAVEDSESSION_LEN-1] = '\0';
315 savedsession[0] = '\0';
319 char *errmsg = save_settings(savedsession, !isdef, cfg);
321 dlg_error_msg(dlg, errmsg);
325 get_sesslist(ssd->sesslist, FALSE);
326 get_sesslist(ssd->sesslist, TRUE);
327 dlg_refresh(ssd->editbox, dlg);
328 dlg_refresh(ssd->listbox, dlg);
329 } else if (ctrl == ssd->delbutton) {
330 int i = dlg_listbox_index(ssd->listbox, dlg);
334 del_settings(ssd->sesslist->sessions[i]);
335 get_sesslist(ssd->sesslist, FALSE);
336 get_sesslist(ssd->sesslist, TRUE);
337 dlg_refresh(ssd->listbox, dlg);
339 } else if (ctrl == ssd->okbutton) {
341 /* In a mid-session Change Settings, Apply is always OK. */
346 * Annoying special case. If the `Open' button is
347 * pressed while no host name is currently set, _and_
348 * the session list previously had the focus, _and_
349 * there was a session selected in that which had a
350 * valid host name in it, then load it and go.
352 if (dlg_last_focused(ctrl, dlg) == ssd->listbox && !*cfg->host) {
354 if (!load_selected_session(ssd, savedsession, dlg, &cfg2)) {
358 /* If at this point we have a valid session, go! */
360 *cfg = cfg2; /* structure copy */
361 cfg->remote_cmd_ptr = cfg->remote_cmd; /* nasty */
368 * Otherwise, do the normal thing: if we have a valid
369 * session, get going.
375 } else if (ctrl == ssd->cancelbutton) {
381 struct charclass_data {
382 union control *listbox, *editbox, *button;
385 static void charclass_handler(union control *ctrl, void *dlg,
386 void *data, int event)
388 Config *cfg = (Config *)data;
389 struct charclass_data *ccd =
390 (struct charclass_data *)ctrl->generic.context.p;
392 if (event == EVENT_REFRESH) {
393 if (ctrl == ccd->listbox) {
395 dlg_update_start(ctrl, dlg);
396 dlg_listbox_clear(ctrl, dlg);
397 for (i = 0; i < 128; i++) {
399 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
400 (i >= 0x21 && i != 0x7F) ? i : ' ', cfg->wordness[i]);
401 dlg_listbox_add(ctrl, dlg, str);
403 dlg_update_done(ctrl, dlg);
405 } else if (event == EVENT_ACTION) {
406 if (ctrl == ccd->button) {
409 dlg_editbox_get(ccd->editbox, dlg, str, sizeof(str));
411 for (i = 0; i < 128; i++) {
412 if (dlg_listbox_issel(ccd->listbox, dlg, i))
413 cfg->wordness[i] = n;
415 dlg_refresh(ccd->listbox, dlg);
421 union control *listbox, *redit, *gedit, *bedit, *button;
424 static const char *const colours[] = {
425 "Default Foreground", "Default Bold Foreground",
426 "Default Background", "Default Bold Background",
427 "Cursor Text", "Cursor Colour",
428 "ANSI Black", "ANSI Black Bold",
429 "ANSI Red", "ANSI Red Bold",
430 "ANSI Green", "ANSI Green Bold",
431 "ANSI Yellow", "ANSI Yellow Bold",
432 "ANSI Blue", "ANSI Blue Bold",
433 "ANSI Magenta", "ANSI Magenta Bold",
434 "ANSI Cyan", "ANSI Cyan Bold",
435 "ANSI White", "ANSI White Bold"
438 static void colour_handler(union control *ctrl, void *dlg,
439 void *data, int event)
441 Config *cfg = (Config *)data;
442 struct colour_data *cd =
443 (struct colour_data *)ctrl->generic.context.p;
444 int update = FALSE, r, g, b;
446 if (event == EVENT_REFRESH) {
447 if (ctrl == cd->listbox) {
449 dlg_update_start(ctrl, dlg);
450 dlg_listbox_clear(ctrl, dlg);
451 for (i = 0; i < lenof(colours); i++)
452 dlg_listbox_add(ctrl, dlg, colours[i]);
453 dlg_update_done(ctrl, dlg);
454 dlg_editbox_set(cd->redit, dlg, "");
455 dlg_editbox_set(cd->gedit, dlg, "");
456 dlg_editbox_set(cd->bedit, dlg, "");
458 } else if (event == EVENT_SELCHANGE) {
459 if (ctrl == cd->listbox) {
460 /* The user has selected a colour. Update the RGB text. */
461 int i = dlg_listbox_index(ctrl, dlg);
466 r = cfg->colours[i][0];
467 g = cfg->colours[i][1];
468 b = cfg->colours[i][2];
471 } else if (event == EVENT_VALCHANGE) {
472 if (ctrl == cd->redit || ctrl == cd->gedit || ctrl == cd->bedit) {
473 /* The user has changed the colour using the edit boxes. */
477 dlg_editbox_get(ctrl, dlg, buf, lenof(buf));
478 cval = atoi(buf) & 255;
480 i = dlg_listbox_index(cd->listbox, dlg);
482 if (ctrl == cd->redit)
483 cfg->colours[i][0] = cval;
484 else if (ctrl == cd->gedit)
485 cfg->colours[i][1] = cval;
486 else if (ctrl == cd->bedit)
487 cfg->colours[i][2] = cval;
490 } else if (event == EVENT_ACTION) {
491 if (ctrl == cd->button) {
492 int i = dlg_listbox_index(cd->listbox, dlg);
498 * Start a colour selector, which will send us an
499 * EVENT_CALLBACK when it's finished and allow us to
500 * pick up the results.
502 dlg_coloursel_start(ctrl, dlg,
507 } else if (event == EVENT_CALLBACK) {
508 if (ctrl == cd->button) {
509 int i = dlg_listbox_index(cd->listbox, dlg);
511 * Collect the results of the colour selector. Will
512 * return nonzero on success, or zero if the colour
513 * selector did nothing (user hit Cancel, for example).
515 if (dlg_coloursel_results(ctrl, dlg, &r, &g, &b)) {
516 cfg->colours[i][0] = r;
517 cfg->colours[i][1] = g;
518 cfg->colours[i][2] = b;
526 sprintf(buf, "%d", r); dlg_editbox_set(cd->redit, dlg, buf);
527 sprintf(buf, "%d", g); dlg_editbox_set(cd->gedit, dlg, buf);
528 sprintf(buf, "%d", b); dlg_editbox_set(cd->bedit, dlg, buf);
532 struct environ_data {
533 union control *varbox, *valbox, *addbutton, *rembutton, *listbox;
536 static void environ_handler(union control *ctrl, void *dlg,
537 void *data, int event)
539 Config *cfg = (Config *)data;
540 struct environ_data *ed =
541 (struct environ_data *)ctrl->generic.context.p;
543 if (event == EVENT_REFRESH) {
544 if (ctrl == ed->listbox) {
545 char *p = cfg->environmt;
546 dlg_update_start(ctrl, dlg);
547 dlg_listbox_clear(ctrl, dlg);
549 dlg_listbox_add(ctrl, dlg, p);
552 dlg_update_done(ctrl, dlg);
554 } else if (event == EVENT_ACTION) {
555 if (ctrl == ed->addbutton) {
556 char str[sizeof(cfg->environmt)];
558 dlg_editbox_get(ed->varbox, dlg, str, sizeof(str)-1);
563 p = str + strlen(str);
565 dlg_editbox_get(ed->valbox, dlg, p, sizeof(str)-1 - (p - str));
576 if ((p - cfg->environmt) + strlen(str) + 2 <
577 sizeof(cfg->environmt)) {
579 p[strlen(str) + 1] = '\0';
580 dlg_listbox_add(ed->listbox, dlg, str);
581 dlg_editbox_set(ed->varbox, dlg, "");
582 dlg_editbox_set(ed->valbox, dlg, "");
584 dlg_error_msg(dlg, "Environment too big");
586 } else if (ctrl == ed->rembutton) {
587 int i = dlg_listbox_index(ed->listbox, dlg);
593 dlg_listbox_del(ed->listbox, dlg, i);
621 struct portfwd_data {
622 union control *addbutton, *rembutton, *listbox;
623 union control *sourcebox, *destbox, *direction;
626 static void portfwd_handler(union control *ctrl, void *dlg,
627 void *data, int event)
629 Config *cfg = (Config *)data;
630 struct portfwd_data *pfd =
631 (struct portfwd_data *)ctrl->generic.context.p;
633 if (event == EVENT_REFRESH) {
634 if (ctrl == pfd->listbox) {
635 char *p = cfg->portfwd;
636 dlg_update_start(ctrl, dlg);
637 dlg_listbox_clear(ctrl, dlg);
639 dlg_listbox_add(ctrl, dlg, p);
642 dlg_update_done(ctrl, dlg);
643 } else if (ctrl == pfd->direction) {
647 dlg_radiobutton_set(ctrl, dlg, 0);
649 } else if (event == EVENT_ACTION) {
650 if (ctrl == pfd->addbutton) {
651 char str[sizeof(cfg->portfwd)];
653 int whichbutton = dlg_radiobutton_get(pfd->direction, dlg);
654 if (whichbutton == 0)
656 else if (whichbutton == 1)
660 dlg_editbox_get(pfd->sourcebox, dlg, str+1, sizeof(str) - 2);
662 dlg_error_msg(dlg, "You need to specify a source port number");
665 p = str + strlen(str);
668 dlg_editbox_get(pfd->destbox, dlg, p,
669 sizeof(str)-1 - (p - str));
670 if (!*p || !strchr(p, ':')) {
672 "You need to specify a destination address\n"
673 "in the form \"host.name:port\"");
684 if ((p - cfg->portfwd) + strlen(str) + 2 <
685 sizeof(cfg->portfwd)) {
687 p[strlen(str) + 1] = '\0';
688 dlg_listbox_add(pfd->listbox, dlg, str);
689 dlg_editbox_set(pfd->sourcebox, dlg, "");
690 dlg_editbox_set(pfd->destbox, dlg, "");
692 dlg_error_msg(dlg, "Too many forwardings");
694 } else if (ctrl == pfd->rembutton) {
695 int i = dlg_listbox_index(pfd->listbox, dlg);
701 dlg_listbox_del(pfd->listbox, dlg, i);
729 void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
730 int midsession, int protocol)
732 struct controlset *s;
733 struct sessionsaver_data *ssd;
734 struct charclass_data *ccd;
735 struct colour_data *cd;
736 struct environ_data *ed;
737 struct portfwd_data *pfd;
741 ssd = (struct sessionsaver_data *)
742 ctrl_alloc(b, sizeof(struct sessionsaver_data));
743 memset(ssd, 0, sizeof(*ssd));
744 ssd->sesslist = (midsession ? NULL : sesslist);
747 * The standard panel that appears at the bottom of all panels:
748 * Open, Cancel, Apply etc.
750 s = ctrl_getset(b, "", "", "");
751 ctrl_columns(s, 5, 20, 20, 20, 20, 20);
752 ssd->okbutton = ctrl_pushbutton(s,
753 (midsession ? "Apply" : "Open"),
754 (char)(midsession ? 'a' : 'o'),
756 sessionsaver_handler, P(ssd));
757 ssd->okbutton->button.isdefault = TRUE;
758 ssd->okbutton->generic.column = 3;
759 ssd->cancelbutton = ctrl_pushbutton(s, "Cancel", 'c', HELPCTX(no_help),
760 sessionsaver_handler, P(ssd));
761 ssd->cancelbutton->button.iscancel = TRUE;
762 ssd->cancelbutton->generic.column = 4;
763 /* We carefully don't close the 5-column part, so that platform-
764 * specific add-ons can put extra buttons alongside Open and Cancel. */
769 str = dupprintf("Basic options for your %s session", appname);
770 ctrl_settitle(b, "Session", str);
774 s = ctrl_getset(b, "Session", "hostport",
775 "Specify your connection by host name or IP address");
776 ctrl_columns(s, 2, 75, 25);
777 c = ctrl_editbox(s, "Host Name (or IP address)", 'n', 100,
778 HELPCTX(session_hostname),
779 dlg_stdeditbox_handler, I(offsetof(Config,host)),
780 I(sizeof(((Config *)0)->host)));
781 c->generic.column = 0;
782 c = ctrl_editbox(s, "Port", 'p', 100, HELPCTX(session_hostname),
783 dlg_stdeditbox_handler,
784 I(offsetof(Config,port)), I(-1));
785 c->generic.column = 1;
786 ctrl_columns(s, 1, 100);
787 if (backends[3].name == NULL) {
788 ctrl_radiobuttons(s, "Protocol:", NO_SHORTCUT, 3,
789 HELPCTX(session_hostname),
790 protocolbuttons_handler, P(c),
791 "Raw", 'r', I(PROT_RAW),
792 "Telnet", 't', I(PROT_TELNET),
793 "Rlogin", 'i', I(PROT_RLOGIN),
796 ctrl_radiobuttons(s, "Protocol:", NO_SHORTCUT, 4,
797 HELPCTX(session_hostname),
798 protocolbuttons_handler, P(c),
799 "Raw", 'r', I(PROT_RAW),
800 "Telnet", 't', I(PROT_TELNET),
801 "Rlogin", 'i', I(PROT_RLOGIN),
802 "SSH", 's', I(PROT_SSH),
806 s = ctrl_getset(b, "Session", "savedsessions",
807 "Load, save or delete a stored session");
808 ctrl_columns(s, 2, 75, 25);
809 ssd->sesslist = sesslist;
810 ssd->editbox = ctrl_editbox(s, "Saved Sessions", 'e', 100,
811 HELPCTX(session_saved),
812 sessionsaver_handler, P(ssd), P(NULL));
813 ssd->editbox->generic.column = 0;
814 /* Reset columns so that the buttons are alongside the list, rather
815 * than alongside that edit box. */
816 ctrl_columns(s, 1, 100);
817 ctrl_columns(s, 2, 75, 25);
818 ssd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
819 HELPCTX(session_saved),
820 sessionsaver_handler, P(ssd));
821 ssd->listbox->generic.column = 0;
822 ssd->listbox->listbox.height = 7;
823 ssd->loadbutton = ctrl_pushbutton(s, "Load", 'l',
824 HELPCTX(session_saved),
825 sessionsaver_handler, P(ssd));
826 ssd->loadbutton->generic.column = 1;
827 ssd->savebutton = ctrl_pushbutton(s, "Save", 'v',
828 HELPCTX(session_saved),
829 sessionsaver_handler, P(ssd));
830 ssd->savebutton->generic.column = 1;
831 ssd->delbutton = ctrl_pushbutton(s, "Delete", 'd',
832 HELPCTX(session_saved),
833 sessionsaver_handler, P(ssd));
834 ssd->delbutton->generic.column = 1;
835 ctrl_columns(s, 1, 100);
838 s = ctrl_getset(b, "Session", "otheropts", NULL);
839 c = ctrl_radiobuttons(s, "Close window on exit:", 'w', 4,
840 HELPCTX(session_coe),
841 dlg_stdradiobutton_handler,
842 I(offsetof(Config, close_on_exit)),
843 "Always", I(FORCE_ON),
844 "Never", I(FORCE_OFF),
845 "Only on clean exit", I(AUTO), NULL);
848 * The Session/Logging panel.
850 ctrl_settitle(b, "Session/Logging", "Options controlling session logging");
852 s = ctrl_getset(b, "Session/Logging", "main", NULL);
854 * The logging buttons change depending on whether SSH packet
855 * logging can sensibly be available.
859 if ((midsession && protocol == PROT_SSH) ||
860 (!midsession && backends[3].name != NULL))
861 sshlogname = "Log SSH packet data";
863 sshlogname = NULL; /* this will disable the button */
864 ctrl_radiobuttons(s, "Session logging:", NO_SHORTCUT, 1,
865 HELPCTX(logging_main),
866 dlg_stdradiobutton_handler,
867 I(offsetof(Config, logtype)),
868 "Logging turned off completely", 't', I(LGTYP_NONE),
869 "Log printable output only", 'p', I(LGTYP_ASCII),
870 "Log all session output", 'l', I(LGTYP_DEBUG),
871 sshlogname, 's', I(LGTYP_PACKETS),
874 ctrl_filesel(s, "Log file name:", 'f',
875 NULL, TRUE, "Select session log file name",
876 HELPCTX(logging_filename),
877 dlg_stdfilesel_handler, I(offsetof(Config, logfilename)));
878 ctrl_text(s, "(Log file name can contain &Y, &M, &D for date,"
879 " &T for time, and &H for host name)",
880 HELPCTX(logging_filename));
881 ctrl_radiobuttons(s, "What to do if the log file already exists:", 'e', 1,
882 HELPCTX(logging_exists),
883 dlg_stdradiobutton_handler, I(offsetof(Config,logxfovr)),
884 "Always overwrite it", I(LGXF_OVR),
885 "Always append to the end of it", I(LGXF_APN),
886 "Ask the user every time", I(LGXF_ASK), NULL);
888 if ((midsession && protocol == PROT_SSH) ||
889 (!midsession && backends[3].name != NULL)) {
890 s = ctrl_getset(b, "Session/Logging", "ssh",
891 "Options specific to SSH packet logging");
892 ctrl_checkbox(s, "Omit known password fields", 'k',
893 HELPCTX(logging_ssh_omit_password),
894 dlg_stdcheckbox_handler, I(offsetof(Config,logomitpass)));
895 ctrl_checkbox(s, "Omit session data", 'd',
896 HELPCTX(logging_ssh_omit_data),
897 dlg_stdcheckbox_handler, I(offsetof(Config,logomitdata)));
901 * The Terminal panel.
903 ctrl_settitle(b, "Terminal", "Options controlling the terminal emulation");
905 s = ctrl_getset(b, "Terminal", "general", "Set various terminal options");
906 ctrl_checkbox(s, "Auto wrap mode initially on", 'w',
907 HELPCTX(terminal_autowrap),
908 dlg_stdcheckbox_handler, I(offsetof(Config,wrap_mode)));
909 ctrl_checkbox(s, "DEC Origin Mode initially on", 'd',
910 HELPCTX(terminal_decom),
911 dlg_stdcheckbox_handler, I(offsetof(Config,dec_om)));
912 ctrl_checkbox(s, "Implicit CR in every LF", 'r',
913 HELPCTX(terminal_lfhascr),
914 dlg_stdcheckbox_handler, I(offsetof(Config,lfhascr)));
915 ctrl_checkbox(s, "Use background colour to erase screen", 'e',
916 HELPCTX(terminal_bce),
917 dlg_stdcheckbox_handler, I(offsetof(Config,bce)));
918 ctrl_checkbox(s, "Enable blinking text", 'n',
919 HELPCTX(terminal_blink),
920 dlg_stdcheckbox_handler, I(offsetof(Config,blinktext)));
921 ctrl_editbox(s, "Answerback to ^E:", 's', 100,
922 HELPCTX(terminal_answerback),
923 dlg_stdeditbox_handler, I(offsetof(Config,answerback)),
924 I(sizeof(((Config *)0)->answerback)));
926 s = ctrl_getset(b, "Terminal", "ldisc", "Line discipline options");
927 ctrl_radiobuttons(s, "Local echo:", 'l', 3,
928 HELPCTX(terminal_localecho),
929 dlg_stdradiobutton_handler,I(offsetof(Config,localecho)),
931 "Force on", I(FORCE_ON),
932 "Force off", I(FORCE_OFF), NULL);
933 ctrl_radiobuttons(s, "Local line editing:", 't', 3,
934 HELPCTX(terminal_localedit),
935 dlg_stdradiobutton_handler,I(offsetof(Config,localedit)),
937 "Force on", I(FORCE_ON),
938 "Force off", I(FORCE_OFF), NULL);
940 s = ctrl_getset(b, "Terminal", "printing", "Remote-controlled printing");
941 ctrl_combobox(s, "Printer to send ANSI printer output to:", 'p', 100,
942 HELPCTX(terminal_printing),
943 printerbox_handler, P(NULL), P(NULL));
946 * The Terminal/Keyboard panel.
948 ctrl_settitle(b, "Terminal/Keyboard",
949 "Options controlling the effects of keys");
951 s = ctrl_getset(b, "Terminal/Keyboard", "mappings",
952 "Change the sequences sent by:");
953 ctrl_radiobuttons(s, "The Backspace key", 'b', 2,
954 HELPCTX(keyboard_backspace),
955 dlg_stdradiobutton_handler,
956 I(offsetof(Config, bksp_is_delete)),
957 "Control-H", I(0), "Control-? (127)", I(1), NULL);
958 ctrl_radiobuttons(s, "The Home and End keys", 'e', 2,
959 HELPCTX(keyboard_homeend),
960 dlg_stdradiobutton_handler,
961 I(offsetof(Config, rxvt_homeend)),
962 "Standard", I(0), "rxvt", I(1), NULL);
963 ctrl_radiobuttons(s, "The Function keys and keypad", 'f', 3,
964 HELPCTX(keyboard_funkeys),
965 dlg_stdradiobutton_handler,
966 I(offsetof(Config, funky_type)),
967 "ESC[n~", I(0), "Linux", I(1), "Xterm R6", I(2),
968 "VT400", I(3), "VT100+", I(4), "SCO", I(5), NULL);
970 s = ctrl_getset(b, "Terminal/Keyboard", "appkeypad",
971 "Application keypad settings:");
972 ctrl_radiobuttons(s, "Initial state of cursor keys:", 'r', 3,
973 HELPCTX(keyboard_appcursor),
974 dlg_stdradiobutton_handler,
975 I(offsetof(Config, app_cursor)),
976 "Normal", I(0), "Application", I(1), NULL);
977 ctrl_radiobuttons(s, "Initial state of numeric keypad:", 'n', 3,
978 HELPCTX(keyboard_appkeypad),
979 numeric_keypad_handler, P(NULL),
980 "Normal", I(0), "Application", I(1), "NetHack", I(2),
984 * The Terminal/Bell panel.
986 ctrl_settitle(b, "Terminal/Bell",
987 "Options controlling the terminal bell");
989 s = ctrl_getset(b, "Terminal/Bell", "style", "Set the style of bell");
990 ctrl_radiobuttons(s, "Action to happen when a bell occurs:", 'b', 1,
992 dlg_stdradiobutton_handler, I(offsetof(Config, beep)),
993 "None (bell disabled)", I(BELL_DISABLED),
994 "Make default system alert sound", I(BELL_DEFAULT),
995 "Visual bell (flash window)", I(BELL_VISUAL), NULL);
997 s = ctrl_getset(b, "Terminal/Bell", "overload",
998 "Control the bell overload behaviour");
999 ctrl_checkbox(s, "Bell is temporarily disabled when over-used", 'd',
1000 HELPCTX(bell_overload),
1001 dlg_stdcheckbox_handler, I(offsetof(Config,bellovl)));
1002 ctrl_editbox(s, "Over-use means this many bells...", 'm', 20,
1003 HELPCTX(bell_overload),
1004 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_n)), I(-1));
1005 ctrl_editbox(s, "... in this many seconds", 't', 20,
1006 HELPCTX(bell_overload),
1007 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_t)),
1009 ctrl_text(s, "The bell is re-enabled after a few seconds of silence.",
1010 HELPCTX(bell_overload));
1011 ctrl_editbox(s, "Seconds of silence required", 's', 20,
1012 HELPCTX(bell_overload),
1013 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_s)),
1017 * The Terminal/Features panel.
1019 ctrl_settitle(b, "Terminal/Features",
1020 "Enabling and disabling advanced terminal features");
1022 s = ctrl_getset(b, "Terminal/Features", "main", NULL);
1023 ctrl_checkbox(s, "Disable application cursor keys mode", 'u',
1024 HELPCTX(features_application),
1025 dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_c)));
1026 ctrl_checkbox(s, "Disable application keypad mode", 'k',
1027 HELPCTX(features_application),
1028 dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_k)));
1029 ctrl_checkbox(s, "Disable xterm-style mouse reporting", 'x',
1030 HELPCTX(features_mouse),
1031 dlg_stdcheckbox_handler, I(offsetof(Config,no_mouse_rep)));
1032 ctrl_checkbox(s, "Disable remote-controlled terminal resizing", 's',
1033 HELPCTX(features_resize),
1034 dlg_stdcheckbox_handler,
1035 I(offsetof(Config,no_remote_resize)));
1036 ctrl_checkbox(s, "Disable switching to alternate terminal screen", 'w',
1037 HELPCTX(features_altscreen),
1038 dlg_stdcheckbox_handler, I(offsetof(Config,no_alt_screen)));
1039 ctrl_checkbox(s, "Disable remote-controlled window title changing", 't',
1040 HELPCTX(features_retitle),
1041 dlg_stdcheckbox_handler,
1042 I(offsetof(Config,no_remote_wintitle)));
1043 ctrl_checkbox(s, "Disable remote window title querying (SECURITY)",
1044 'q', HELPCTX(features_qtitle), dlg_stdcheckbox_handler,
1045 I(offsetof(Config,no_remote_qtitle)));
1046 ctrl_checkbox(s, "Disable destructive backspace on server sending ^?",'b',
1047 HELPCTX(features_dbackspace),
1048 dlg_stdcheckbox_handler, I(offsetof(Config,no_dbackspace)));
1049 ctrl_checkbox(s, "Disable remote-controlled character set configuration",
1050 'r', HELPCTX(features_charset), dlg_stdcheckbox_handler,
1051 I(offsetof(Config,no_remote_charset)));
1052 ctrl_checkbox(s, "Disable Arabic text shaping",
1053 'l', HELPCTX(features_arabicshaping), dlg_stdcheckbox_handler,
1054 I(offsetof(Config, arabicshaping)));
1055 ctrl_checkbox(s, "Disable bidirectional text display",
1056 'd', HELPCTX(features_bidi), dlg_stdcheckbox_handler,
1057 I(offsetof(Config, bidi)));
1062 str = dupprintf("Options controlling %s's window", appname);
1063 ctrl_settitle(b, "Window", str);
1066 s = ctrl_getset(b, "Window", "size", "Set the size of the window");
1067 ctrl_columns(s, 2, 50, 50);
1068 c = ctrl_editbox(s, "Rows", 'r', 100,
1069 HELPCTX(window_size),
1070 dlg_stdeditbox_handler, I(offsetof(Config,height)),I(-1));
1071 c->generic.column = 0;
1072 c = ctrl_editbox(s, "Columns", 'm', 100,
1073 HELPCTX(window_size),
1074 dlg_stdeditbox_handler, I(offsetof(Config,width)), I(-1));
1075 c->generic.column = 1;
1076 ctrl_columns(s, 1, 100);
1078 s = ctrl_getset(b, "Window", "scrollback",
1079 "Control the scrollback in the window");
1080 ctrl_editbox(s, "Lines of scrollback", 's', 50,
1081 HELPCTX(window_scrollback),
1082 dlg_stdeditbox_handler, I(offsetof(Config,savelines)), I(-1));
1083 ctrl_checkbox(s, "Display scrollbar", 'd',
1084 HELPCTX(window_scrollback),
1085 dlg_stdcheckbox_handler, I(offsetof(Config,scrollbar)));
1086 ctrl_checkbox(s, "Reset scrollback on keypress", 'k',
1087 HELPCTX(window_scrollback),
1088 dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_key)));
1089 ctrl_checkbox(s, "Reset scrollback on display activity", 'p',
1090 HELPCTX(window_scrollback),
1091 dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_disp)));
1092 ctrl_checkbox(s, "Push erased text into scrollback", 'e',
1093 HELPCTX(window_erased),
1094 dlg_stdcheckbox_handler,
1095 I(offsetof(Config,erase_to_scrollback)));
1098 * The Window/Appearance panel.
1100 str = dupprintf("Configure the appearance of %s's window", appname);
1101 ctrl_settitle(b, "Window/Appearance", str);
1104 s = ctrl_getset(b, "Window/Appearance", "cursor",
1105 "Adjust the use of the cursor");
1106 ctrl_radiobuttons(s, "Cursor appearance:", NO_SHORTCUT, 3,
1107 HELPCTX(appearance_cursor),
1108 dlg_stdradiobutton_handler,
1109 I(offsetof(Config, cursor_type)),
1111 "Underline", 'u', I(1),
1112 "Vertical line", 'v', I(2), NULL);
1113 ctrl_checkbox(s, "Cursor blinks", 'b',
1114 HELPCTX(appearance_cursor),
1115 dlg_stdcheckbox_handler, I(offsetof(Config,blink_cur)));
1117 s = ctrl_getset(b, "Window/Appearance", "font",
1119 ctrl_fontsel(s, "Font used in the terminal window", 'n',
1120 HELPCTX(appearance_font),
1121 dlg_stdfontsel_handler, I(offsetof(Config, font)));
1123 s = ctrl_getset(b, "Window/Appearance", "mouse",
1124 "Adjust the use of the mouse pointer");
1125 ctrl_checkbox(s, "Hide mouse pointer when typing in window", 'p',
1126 HELPCTX(appearance_hidemouse),
1127 dlg_stdcheckbox_handler, I(offsetof(Config,hide_mouseptr)));
1129 s = ctrl_getset(b, "Window/Appearance", "border",
1130 "Adjust the window border");
1131 ctrl_editbox(s, "Gap between text and window edge:", NO_SHORTCUT, 20,
1132 HELPCTX(appearance_border),
1133 dlg_stdeditbox_handler,
1134 I(offsetof(Config,window_border)), I(-1));
1137 * The Window/Behaviour panel.
1139 str = dupprintf("Configure the behaviour of %s's window", appname);
1140 ctrl_settitle(b, "Window/Behaviour", str);
1143 s = ctrl_getset(b, "Window/Behaviour", "title",
1144 "Adjust the behaviour of the window title");
1145 ctrl_editbox(s, "Window title:", 't', 100,
1146 HELPCTX(appearance_title),
1147 dlg_stdeditbox_handler, I(offsetof(Config,wintitle)),
1148 I(sizeof(((Config *)0)->wintitle)));
1149 ctrl_checkbox(s, "Separate window and icon titles", 'i',
1150 HELPCTX(appearance_title),
1151 dlg_stdcheckbox_handler,
1152 I(CHECKBOX_INVERT | offsetof(Config,win_name_always)));
1154 s = ctrl_getset(b, "Window/Behaviour", "main", NULL);
1155 ctrl_checkbox(s, "Warn before closing window", 'w',
1156 HELPCTX(behaviour_closewarn),
1157 dlg_stdcheckbox_handler, I(offsetof(Config,warn_on_close)));
1160 * The Window/Translation panel.
1162 ctrl_settitle(b, "Window/Translation",
1163 "Options controlling character set translation");
1165 s = ctrl_getset(b, "Window/Translation", "trans",
1166 "Character set translation on received data");
1167 ctrl_combobox(s, "Received data assumed to be in which character set:",
1168 'r', 100, HELPCTX(translation_codepage),
1169 codepage_handler, P(NULL), P(NULL));
1171 str = dupprintf("Adjust how %s handles line drawing characters", appname);
1172 s = ctrl_getset(b, "Window/Translation", "linedraw", str);
1174 ctrl_radiobuttons(s, "Handling of line drawing characters:", NO_SHORTCUT,1,
1175 HELPCTX(translation_linedraw),
1176 dlg_stdradiobutton_handler,
1177 I(offsetof(Config, vtmode)),
1178 "Use Unicode line drawing code points",'u',I(VT_UNICODE),
1179 "Poor man's line drawing (+, - and |)",'p',I(VT_POORMAN),
1181 ctrl_checkbox(s, "Copy and paste line drawing characters as lqqqk",'d',
1182 HELPCTX(selection_linedraw),
1183 dlg_stdcheckbox_handler, I(offsetof(Config,rawcnp)));
1186 * The Window/Selection panel.
1188 ctrl_settitle(b, "Window/Selection", "Options controlling copy and paste");
1190 s = ctrl_getset(b, "Window/Selection", "mouse",
1191 "Control use of mouse");
1192 ctrl_checkbox(s, "Shift overrides application's use of mouse", 'p',
1193 HELPCTX(selection_shiftdrag),
1194 dlg_stdcheckbox_handler, I(offsetof(Config,mouse_override)));
1195 ctrl_radiobuttons(s,
1196 "Default selection mode (Alt+drag does the other one):",
1198 HELPCTX(selection_rect),
1199 dlg_stdradiobutton_handler,
1200 I(offsetof(Config, rect_select)),
1201 "Normal", 'n', I(0),
1202 "Rectangular block", 'r', I(1), NULL);
1204 s = ctrl_getset(b, "Window/Selection", "charclass",
1205 "Control the select-one-word-at-a-time mode");
1206 ccd = (struct charclass_data *)
1207 ctrl_alloc(b, sizeof(struct charclass_data));
1208 ccd->listbox = ctrl_listbox(s, "Character classes:", 'e',
1209 HELPCTX(selection_charclasses),
1210 charclass_handler, P(ccd));
1211 ccd->listbox->listbox.multisel = 1;
1212 ccd->listbox->listbox.ncols = 4;
1213 ccd->listbox->listbox.percentages = snewn(4, int);
1214 ccd->listbox->listbox.percentages[0] = 15;
1215 ccd->listbox->listbox.percentages[1] = 25;
1216 ccd->listbox->listbox.percentages[2] = 20;
1217 ccd->listbox->listbox.percentages[3] = 40;
1218 ctrl_columns(s, 2, 67, 33);
1219 ccd->editbox = ctrl_editbox(s, "Set to class", 't', 50,
1220 HELPCTX(selection_charclasses),
1221 charclass_handler, P(ccd), P(NULL));
1222 ccd->editbox->generic.column = 0;
1223 ccd->button = ctrl_pushbutton(s, "Set", 's',
1224 HELPCTX(selection_charclasses),
1225 charclass_handler, P(ccd));
1226 ccd->button->generic.column = 1;
1227 ctrl_columns(s, 1, 100);
1230 * The Window/Colours panel.
1232 ctrl_settitle(b, "Window/Colours", "Options controlling use of colours");
1234 s = ctrl_getset(b, "Window/Colours", "general",
1235 "General options for colour usage");
1236 ctrl_checkbox(s, "Allow terminal to specify ANSI colours", 'i',
1237 HELPCTX(colours_ansi),
1238 dlg_stdcheckbox_handler, I(offsetof(Config,ansi_colour)));
1239 ctrl_checkbox(s, "Bolded text is a different colour", 'b',
1240 HELPCTX(colours_bold),
1241 dlg_stdcheckbox_handler, I(offsetof(Config,bold_colour)));
1243 str = dupprintf("Adjust the precise colours %s displays", appname);
1244 s = ctrl_getset(b, "Window/Colours", "adjust", str);
1246 ctrl_text(s, "Select a colour from the list, and then click the"
1247 " Modify button to change its appearance.",
1248 HELPCTX(colours_config));
1249 ctrl_columns(s, 2, 67, 33);
1250 cd = (struct colour_data *)ctrl_alloc(b, sizeof(struct colour_data));
1251 cd->listbox = ctrl_listbox(s, "Select a colour to adjust:", 'u',
1252 HELPCTX(colours_config), colour_handler, P(cd));
1253 cd->listbox->generic.column = 0;
1254 cd->listbox->listbox.height = 7;
1255 c = ctrl_text(s, "RGB value:", HELPCTX(colours_config));
1256 c->generic.column = 1;
1257 cd->redit = ctrl_editbox(s, "Red", 'r', 50, HELPCTX(colours_config),
1258 colour_handler, P(cd), P(NULL));
1259 cd->redit->generic.column = 1;
1260 cd->gedit = ctrl_editbox(s, "Green", 'n', 50, HELPCTX(colours_config),
1261 colour_handler, P(cd), P(NULL));
1262 cd->gedit->generic.column = 1;
1263 cd->bedit = ctrl_editbox(s, "Blue", 'e', 50, HELPCTX(colours_config),
1264 colour_handler, P(cd), P(NULL));
1265 cd->bedit->generic.column = 1;
1266 cd->button = ctrl_pushbutton(s, "Modify", 'm', HELPCTX(colours_config),
1267 colour_handler, P(cd));
1268 cd->button->generic.column = 1;
1269 ctrl_columns(s, 1, 100);
1272 * The Connection panel. This doesn't show up if we're in a
1273 * non-network utility such as pterm. We tell this by being
1274 * passed a protocol < 0.
1276 if (protocol >= 0) {
1277 ctrl_settitle(b, "Connection", "Options controlling the connection");
1280 s = ctrl_getset(b, "Connection", "data",
1281 "Data to send to the server");
1282 ctrl_editbox(s, "Terminal-type string", 't', 50,
1283 HELPCTX(connection_termtype),
1284 dlg_stdeditbox_handler, I(offsetof(Config,termtype)),
1285 I(sizeof(((Config *)0)->termtype)));
1286 ctrl_editbox(s, "Terminal speeds", 's', 50,
1287 HELPCTX(connection_termspeed),
1288 dlg_stdeditbox_handler, I(offsetof(Config,termspeed)),
1289 I(sizeof(((Config *)0)->termspeed)));
1290 ctrl_editbox(s, "Auto-login username", 'u', 50,
1291 HELPCTX(connection_username),
1292 dlg_stdeditbox_handler, I(offsetof(Config,username)),
1293 I(sizeof(((Config *)0)->username)));
1295 ctrl_text(s, "Environment variables:", HELPCTX(telnet_environ));
1296 ctrl_columns(s, 2, 80, 20);
1297 ed = (struct environ_data *)
1298 ctrl_alloc(b, sizeof(struct environ_data));
1299 ed->varbox = ctrl_editbox(s, "Variable", 'v', 60,
1300 HELPCTX(telnet_environ),
1301 environ_handler, P(ed), P(NULL));
1302 ed->varbox->generic.column = 0;
1303 ed->valbox = ctrl_editbox(s, "Value", 'l', 60,
1304 HELPCTX(telnet_environ),
1305 environ_handler, P(ed), P(NULL));
1306 ed->valbox->generic.column = 0;
1307 ed->addbutton = ctrl_pushbutton(s, "Add", 'd',
1308 HELPCTX(telnet_environ),
1309 environ_handler, P(ed));
1310 ed->addbutton->generic.column = 1;
1311 ed->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1312 HELPCTX(telnet_environ),
1313 environ_handler, P(ed));
1314 ed->rembutton->generic.column = 1;
1315 ctrl_columns(s, 1, 100);
1316 ed->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1317 HELPCTX(telnet_environ),
1318 environ_handler, P(ed));
1319 ed->listbox->listbox.height = 3;
1320 ed->listbox->listbox.ncols = 2;
1321 ed->listbox->listbox.percentages = snewn(2, int);
1322 ed->listbox->listbox.percentages[0] = 30;
1323 ed->listbox->listbox.percentages[1] = 70;
1326 s = ctrl_getset(b, "Connection", "keepalive",
1327 "Sending of null packets to keep session active");
1328 ctrl_editbox(s, "Seconds between keepalives (0 to turn off)", 'k', 20,
1329 HELPCTX(connection_keepalive),
1330 dlg_stdeditbox_handler, I(offsetof(Config,ping_interval)),
1334 s = ctrl_getset(b, "Connection", "tcp",
1335 "Low-level TCP connection options");
1336 ctrl_checkbox(s, "Disable Nagle's algorithm (TCP_NODELAY option)",
1337 'n', HELPCTX(connection_nodelay),
1338 dlg_stdcheckbox_handler,
1339 I(offsetof(Config,tcp_nodelay)));
1340 ctrl_checkbox(s, "Enable TCP keepalives (SO_KEEPALIVE option)",
1341 'p', HELPCTX(connection_tcpkeepalive),
1342 dlg_stdcheckbox_handler,
1343 I(offsetof(Config,tcp_keepalives)));
1350 * The Connection/Proxy panel.
1352 ctrl_settitle(b, "Connection/Proxy",
1353 "Options controlling proxy usage");
1355 s = ctrl_getset(b, "Connection/Proxy", "basics", NULL);
1356 ctrl_radiobuttons(s, "Proxy type:", 't', 3,
1357 HELPCTX(proxy_type),
1358 dlg_stdradiobutton_handler,
1359 I(offsetof(Config, proxy_type)),
1360 "None", I(PROXY_NONE),
1361 "SOCKS 4", I(PROXY_SOCKS4),
1362 "SOCKS 5", I(PROXY_SOCKS5),
1363 "HTTP", I(PROXY_HTTP),
1364 "Telnet", I(PROXY_TELNET),
1366 ctrl_columns(s, 2, 80, 20);
1367 c = ctrl_editbox(s, "Proxy hostname", 'y', 100,
1368 HELPCTX(proxy_main),
1369 dlg_stdeditbox_handler,
1370 I(offsetof(Config,proxy_host)),
1371 I(sizeof(((Config *)0)->proxy_host)));
1372 c->generic.column = 0;
1373 c = ctrl_editbox(s, "Port", 'p', 100,
1374 HELPCTX(proxy_main),
1375 dlg_stdeditbox_handler,
1376 I(offsetof(Config,proxy_port)),
1378 c->generic.column = 1;
1379 ctrl_columns(s, 1, 100);
1380 ctrl_editbox(s, "Exclude Hosts/IPs", 'e', 100,
1381 HELPCTX(proxy_exclude),
1382 dlg_stdeditbox_handler,
1383 I(offsetof(Config,proxy_exclude_list)),
1384 I(sizeof(((Config *)0)->proxy_exclude_list)));
1385 ctrl_checkbox(s, "Consider proxying local host connections", 'x',
1386 HELPCTX(proxy_exclude),
1387 dlg_stdcheckbox_handler,
1388 I(offsetof(Config,even_proxy_localhost)));
1389 ctrl_radiobuttons(s, "Do DNS name lookup at proxy end:", 'd', 3,
1391 dlg_stdradiobutton_handler,
1392 I(offsetof(Config, proxy_dns)),
1395 "Yes", I(FORCE_ON), NULL);
1396 ctrl_editbox(s, "Username", 'u', 60,
1397 HELPCTX(proxy_auth),
1398 dlg_stdeditbox_handler,
1399 I(offsetof(Config,proxy_username)),
1400 I(sizeof(((Config *)0)->proxy_username)));
1401 c = ctrl_editbox(s, "Password", 'w', 60,
1402 HELPCTX(proxy_auth),
1403 dlg_stdeditbox_handler,
1404 I(offsetof(Config,proxy_password)),
1405 I(sizeof(((Config *)0)->proxy_password)));
1406 c->editbox.password = 1;
1407 ctrl_editbox(s, "Telnet command", 'm', 100,
1408 HELPCTX(proxy_command),
1409 dlg_stdeditbox_handler,
1410 I(offsetof(Config,proxy_telnet_command)),
1411 I(sizeof(((Config *)0)->proxy_telnet_command)));
1415 * The Telnet panel exists in the base config box, and in a
1416 * mid-session reconfig box _if_ we're using Telnet.
1418 if (!midsession || protocol == PROT_TELNET) {
1420 * The Connection/Telnet panel.
1422 ctrl_settitle(b, "Connection/Telnet",
1423 "Options controlling Telnet connections");
1425 s = ctrl_getset(b, "Connection/Telnet", "protocol",
1426 "Telnet protocol adjustments");
1429 ctrl_radiobuttons(s, "Handling of OLD_ENVIRON ambiguity:",
1431 HELPCTX(telnet_oldenviron),
1432 dlg_stdradiobutton_handler,
1433 I(offsetof(Config, rfc_environ)),
1434 "BSD (commonplace)", 'b', I(0),
1435 "RFC 1408 (unusual)", 'f', I(1), NULL);
1436 ctrl_radiobuttons(s, "Telnet negotiation mode:", 't', 2,
1437 HELPCTX(telnet_passive),
1438 dlg_stdradiobutton_handler,
1439 I(offsetof(Config, passive_telnet)),
1440 "Passive", I(1), "Active", I(0), NULL);
1442 ctrl_checkbox(s, "Keyboard sends Telnet special commands", 'k',
1443 HELPCTX(telnet_specialkeys),
1444 dlg_stdcheckbox_handler,
1445 I(offsetof(Config,telnet_keyboard)));
1446 ctrl_checkbox(s, "Return key sends Telnet New Line instead of ^M",
1447 'm', HELPCTX(telnet_newline),
1448 dlg_stdcheckbox_handler,
1449 I(offsetof(Config,telnet_newline)));
1455 * The Connection/Rlogin panel.
1457 ctrl_settitle(b, "Connection/Rlogin",
1458 "Options controlling Rlogin connections");
1460 s = ctrl_getset(b, "Connection/Rlogin", "data",
1461 "Data to send to the server");
1462 ctrl_editbox(s, "Local username:", 'l', 50,
1463 HELPCTX(rlogin_localuser),
1464 dlg_stdeditbox_handler, I(offsetof(Config,localusername)),
1465 I(sizeof(((Config *)0)->localusername)));
1470 * All the SSH stuff is omitted in PuTTYtel.
1473 if (!midsession && backends[3].name != NULL) {
1476 * The Connection/SSH panel.
1478 ctrl_settitle(b, "Connection/SSH",
1479 "Options controlling SSH connections");
1481 s = ctrl_getset(b, "Connection/SSH", "data",
1482 "Data to send to the server");
1483 ctrl_editbox(s, "Remote command:", 'r', 100,
1484 HELPCTX(ssh_command),
1485 dlg_stdeditbox_handler, I(offsetof(Config,remote_cmd)),
1486 I(sizeof(((Config *)0)->remote_cmd)));
1488 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1489 ctrl_checkbox(s, "Don't allocate a pseudo-terminal", 'p',
1491 dlg_stdcheckbox_handler,
1492 I(offsetof(Config,nopty)));
1493 ctrl_checkbox(s, "Don't start a shell or command at all", 'n',
1494 HELPCTX(ssh_noshell),
1495 dlg_stdcheckbox_handler,
1496 I(offsetof(Config,ssh_no_shell)));
1497 ctrl_checkbox(s, "Enable compression", 'e',
1498 HELPCTX(ssh_compress),
1499 dlg_stdcheckbox_handler,
1500 I(offsetof(Config,compression)));
1501 ctrl_radiobuttons(s, "Preferred SSH protocol version:", NO_SHORTCUT, 4,
1502 HELPCTX(ssh_protocol),
1503 dlg_stdradiobutton_handler,
1504 I(offsetof(Config, sshprot)),
1505 "1 only", 'l', I(0),
1508 "2 only", 'y', I(3), NULL);
1510 s = ctrl_getset(b, "Connection/SSH", "encryption", "Encryption options");
1511 c = ctrl_draglist(s, "Encryption cipher selection policy:", 's',
1512 HELPCTX(ssh_ciphers),
1513 cipherlist_handler, P(NULL));
1514 c->listbox.height = 6;
1516 ctrl_checkbox(s, "Enable legacy use of single-DES in SSH 2", 'i',
1517 HELPCTX(ssh_ciphers),
1518 dlg_stdcheckbox_handler,
1519 I(offsetof(Config,ssh2_des_cbc)));
1522 * The Connection/SSH/Auth panel.
1524 ctrl_settitle(b, "Connection/SSH/Auth",
1525 "Options controlling SSH authentication");
1527 s = ctrl_getset(b, "Connection/SSH/Auth", "methods",
1528 "Authentication methods");
1529 ctrl_checkbox(s, "Attempt TIS or CryptoCard auth (SSH1)", 'm',
1530 HELPCTX(ssh_auth_tis),
1531 dlg_stdcheckbox_handler,
1532 I(offsetof(Config,try_tis_auth)));
1533 ctrl_checkbox(s, "Attempt \"keyboard-interactive\" auth (SSH2)",
1534 'i', HELPCTX(ssh_auth_ki),
1535 dlg_stdcheckbox_handler,
1536 I(offsetof(Config,try_ki_auth)));
1538 s = ctrl_getset(b, "Connection/SSH/Auth", "params",
1539 "Authentication parameters");
1540 ctrl_checkbox(s, "Allow agent forwarding", 'f',
1541 HELPCTX(ssh_auth_agentfwd),
1542 dlg_stdcheckbox_handler, I(offsetof(Config,agentfwd)));
1543 ctrl_checkbox(s, "Allow attempted changes of username in SSH2", 'u',
1544 HELPCTX(ssh_auth_changeuser),
1545 dlg_stdcheckbox_handler,
1546 I(offsetof(Config,change_username)));
1547 ctrl_filesel(s, "Private key file for authentication:", 'k',
1548 FILTER_KEY_FILES, FALSE, "Select private key file",
1549 HELPCTX(ssh_auth_privkey),
1550 dlg_stdfilesel_handler, I(offsetof(Config, keyfile)));
1553 * The Connection/SSH/Tunnels panel.
1555 ctrl_settitle(b, "Connection/SSH/Tunnels",
1556 "Options controlling SSH tunnelling");
1558 s = ctrl_getset(b, "Connection/SSH/Tunnels", "x11", "X11 forwarding");
1559 ctrl_checkbox(s, "Enable X11 forwarding", 'e',
1560 HELPCTX(ssh_tunnels_x11),
1561 dlg_stdcheckbox_handler,I(offsetof(Config,x11_forward)));
1562 ctrl_editbox(s, "X display location", 'x', 50,
1563 HELPCTX(ssh_tunnels_x11),
1564 dlg_stdeditbox_handler, I(offsetof(Config,x11_display)),
1565 I(sizeof(((Config *)0)->x11_display)));
1566 ctrl_radiobuttons(s, "Remote X11 authentication protocol", 'u', 2,
1567 HELPCTX(ssh_tunnels_x11auth),
1568 dlg_stdradiobutton_handler,
1569 I(offsetof(Config, x11_auth)),
1570 "MIT-Magic-Cookie-1", I(X11_MIT),
1571 "XDM-Authorization-1", I(X11_XDM), NULL);
1573 s = ctrl_getset(b, "Connection/SSH/Tunnels", "portfwd",
1575 ctrl_checkbox(s, "Local ports accept connections from other hosts",'t',
1576 HELPCTX(ssh_tunnels_portfwd_localhost),
1577 dlg_stdcheckbox_handler,
1578 I(offsetof(Config,lport_acceptall)));
1579 ctrl_checkbox(s, "Remote ports do the same (SSH v2 only)", 'p',
1580 HELPCTX(ssh_tunnels_portfwd_localhost),
1581 dlg_stdcheckbox_handler,
1582 I(offsetof(Config,rport_acceptall)));
1584 ctrl_columns(s, 3, 55, 20, 25);
1585 c = ctrl_text(s, "Forwarded ports:", HELPCTX(ssh_tunnels_portfwd));
1586 c->generic.column = COLUMN_FIELD(0,2);
1587 /* You want to select from the list, _then_ hit Remove. So tab order
1588 * should be that way round. */
1589 pfd = (struct portfwd_data *)ctrl_alloc(b,sizeof(struct portfwd_data));
1590 pfd->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1591 HELPCTX(ssh_tunnels_portfwd),
1592 portfwd_handler, P(pfd));
1593 pfd->rembutton->generic.column = 2;
1594 pfd->rembutton->generic.tabdelay = 1;
1595 pfd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1596 HELPCTX(ssh_tunnels_portfwd),
1597 portfwd_handler, P(pfd));
1598 pfd->listbox->listbox.height = 3;
1599 pfd->listbox->listbox.ncols = 2;
1600 pfd->listbox->listbox.percentages = snewn(2, int);
1601 pfd->listbox->listbox.percentages[0] = 20;
1602 pfd->listbox->listbox.percentages[1] = 80;
1603 ctrl_tabdelay(s, pfd->rembutton);
1604 ctrl_text(s, "Add new forwarded port:", HELPCTX(ssh_tunnels_portfwd));
1605 /* You want to enter source, destination and type, _then_ hit Add.
1606 * Again, we adjust the tab order to reflect this. */
1607 pfd->addbutton = ctrl_pushbutton(s, "Add", 'd',
1608 HELPCTX(ssh_tunnels_portfwd),
1609 portfwd_handler, P(pfd));
1610 pfd->addbutton->generic.column = 2;
1611 pfd->addbutton->generic.tabdelay = 1;
1612 pfd->sourcebox = ctrl_editbox(s, "Source port", 's', 40,
1613 HELPCTX(ssh_tunnels_portfwd),
1614 portfwd_handler, P(pfd), P(NULL));
1615 pfd->sourcebox->generic.column = 0;
1616 pfd->destbox = ctrl_editbox(s, "Destination", 'i', 67,
1617 HELPCTX(ssh_tunnels_portfwd),
1618 portfwd_handler, P(pfd), P(NULL));
1619 pfd->direction = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
1620 HELPCTX(ssh_tunnels_portfwd),
1621 portfwd_handler, P(pfd),
1622 "Local", 'l', P(NULL),
1623 "Remote", 'm', P(NULL),
1624 "Dynamic", 'y', P(NULL),
1626 ctrl_tabdelay(s, pfd->addbutton);
1627 ctrl_columns(s, 1, 100);
1630 * The Connection/SSH/Bugs panel.
1632 ctrl_settitle(b, "Connection/SSH/Bugs",
1633 "Workarounds for SSH server bugs");
1635 s = ctrl_getset(b, "Connection/SSH/Bugs", "main",
1636 "Detection of known bugs in SSH servers");
1637 ctrl_droplist(s, "Chokes on SSH1 ignore messages", 'i', 20,
1638 HELPCTX(ssh_bugs_ignore1),
1639 sshbug_handler, I(offsetof(Config,sshbug_ignore1)));
1640 ctrl_droplist(s, "Refuses all SSH1 password camouflage", 's', 20,
1641 HELPCTX(ssh_bugs_plainpw1),
1642 sshbug_handler, I(offsetof(Config,sshbug_plainpw1)));
1643 ctrl_droplist(s, "Chokes on SSH1 RSA authentication", 'r', 20,
1644 HELPCTX(ssh_bugs_rsa1),
1645 sshbug_handler, I(offsetof(Config,sshbug_rsa1)));
1646 ctrl_droplist(s, "Miscomputes SSH2 HMAC keys", 'm', 20,
1647 HELPCTX(ssh_bugs_hmac2),
1648 sshbug_handler, I(offsetof(Config,sshbug_hmac2)));
1649 ctrl_droplist(s, "Miscomputes SSH2 encryption keys", 'e', 20,
1650 HELPCTX(ssh_bugs_derivekey2),
1651 sshbug_handler, I(offsetof(Config,sshbug_derivekey2)));
1652 ctrl_droplist(s, "Requires padding on SSH2 RSA signatures", 'p', 20,
1653 HELPCTX(ssh_bugs_rsapad2),
1654 sshbug_handler, I(offsetof(Config,sshbug_rsapad2)));
1655 ctrl_droplist(s, "Chokes on Diffie-Hellman group exchange", 'd', 20,
1656 HELPCTX(ssh_bugs_dhgex2),
1657 sshbug_handler, I(offsetof(Config,sshbug_dhgex2)));
1658 ctrl_droplist(s, "Misuses the session ID in PK auth", 'n', 20,
1659 HELPCTX(ssh_bugs_pksessid2),
1660 sshbug_handler, I(offsetof(Config,sshbug_pksessid2)));