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 */
369 * Otherwise, do the normal thing: if we have a valid
370 * session, get going.
376 } else if (ctrl == ssd->cancelbutton) {
382 struct charclass_data {
383 union control *listbox, *editbox, *button;
386 static void charclass_handler(union control *ctrl, void *dlg,
387 void *data, int event)
389 Config *cfg = (Config *)data;
390 struct charclass_data *ccd =
391 (struct charclass_data *)ctrl->generic.context.p;
393 if (event == EVENT_REFRESH) {
394 if (ctrl == ccd->listbox) {
396 dlg_update_start(ctrl, dlg);
397 dlg_listbox_clear(ctrl, dlg);
398 for (i = 0; i < 128; i++) {
400 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
401 (i >= 0x21 && i != 0x7F) ? i : ' ', cfg->wordness[i]);
402 dlg_listbox_add(ctrl, dlg, str);
404 dlg_update_done(ctrl, dlg);
406 } else if (event == EVENT_ACTION) {
407 if (ctrl == ccd->button) {
410 dlg_editbox_get(ccd->editbox, dlg, str, sizeof(str));
412 for (i = 0; i < 128; i++) {
413 if (dlg_listbox_issel(ccd->listbox, dlg, i))
414 cfg->wordness[i] = n;
416 dlg_refresh(ccd->listbox, dlg);
422 union control *listbox, *redit, *gedit, *bedit, *button;
425 static const char *const colours[] = {
426 "Default Foreground", "Default Bold Foreground",
427 "Default Background", "Default Bold Background",
428 "Cursor Text", "Cursor Colour",
429 "ANSI Black", "ANSI Black Bold",
430 "ANSI Red", "ANSI Red Bold",
431 "ANSI Green", "ANSI Green Bold",
432 "ANSI Yellow", "ANSI Yellow Bold",
433 "ANSI Blue", "ANSI Blue Bold",
434 "ANSI Magenta", "ANSI Magenta Bold",
435 "ANSI Cyan", "ANSI Cyan Bold",
436 "ANSI White", "ANSI White Bold"
439 static void colour_handler(union control *ctrl, void *dlg,
440 void *data, int event)
442 Config *cfg = (Config *)data;
443 struct colour_data *cd =
444 (struct colour_data *)ctrl->generic.context.p;
445 int update = FALSE, r, g, b;
447 if (event == EVENT_REFRESH) {
448 if (ctrl == cd->listbox) {
450 dlg_update_start(ctrl, dlg);
451 dlg_listbox_clear(ctrl, dlg);
452 for (i = 0; i < lenof(colours); i++)
453 dlg_listbox_add(ctrl, dlg, colours[i]);
454 dlg_update_done(ctrl, dlg);
455 dlg_editbox_set(cd->redit, dlg, "");
456 dlg_editbox_set(cd->gedit, dlg, "");
457 dlg_editbox_set(cd->bedit, dlg, "");
459 } else if (event == EVENT_SELCHANGE) {
460 if (ctrl == cd->listbox) {
461 /* The user has selected a colour. Update the RGB text. */
462 int i = dlg_listbox_index(ctrl, dlg);
467 r = cfg->colours[i][0];
468 g = cfg->colours[i][1];
469 b = cfg->colours[i][2];
472 } else if (event == EVENT_VALCHANGE) {
473 if (ctrl == cd->redit || ctrl == cd->gedit || ctrl == cd->bedit) {
474 /* The user has changed the colour using the edit boxes. */
478 dlg_editbox_get(ctrl, dlg, buf, lenof(buf));
479 cval = atoi(buf) & 255;
481 i = dlg_listbox_index(cd->listbox, dlg);
483 if (ctrl == cd->redit)
484 cfg->colours[i][0] = cval;
485 else if (ctrl == cd->gedit)
486 cfg->colours[i][1] = cval;
487 else if (ctrl == cd->bedit)
488 cfg->colours[i][2] = cval;
491 } else if (event == EVENT_ACTION) {
492 if (ctrl == cd->button) {
493 int i = dlg_listbox_index(cd->listbox, dlg);
499 * Start a colour selector, which will send us an
500 * EVENT_CALLBACK when it's finished and allow us to
501 * pick up the results.
503 dlg_coloursel_start(ctrl, dlg,
508 } else if (event == EVENT_CALLBACK) {
509 if (ctrl == cd->button) {
510 int i = dlg_listbox_index(cd->listbox, dlg);
512 * Collect the results of the colour selector. Will
513 * return nonzero on success, or zero if the colour
514 * selector did nothing (user hit Cancel, for example).
516 if (dlg_coloursel_results(ctrl, dlg, &r, &g, &b)) {
517 cfg->colours[i][0] = r;
518 cfg->colours[i][1] = g;
519 cfg->colours[i][2] = b;
527 sprintf(buf, "%d", r); dlg_editbox_set(cd->redit, dlg, buf);
528 sprintf(buf, "%d", g); dlg_editbox_set(cd->gedit, dlg, buf);
529 sprintf(buf, "%d", b); dlg_editbox_set(cd->bedit, dlg, buf);
533 struct environ_data {
534 union control *varbox, *valbox, *addbutton, *rembutton, *listbox;
537 static void environ_handler(union control *ctrl, void *dlg,
538 void *data, int event)
540 Config *cfg = (Config *)data;
541 struct environ_data *ed =
542 (struct environ_data *)ctrl->generic.context.p;
544 if (event == EVENT_REFRESH) {
545 if (ctrl == ed->listbox) {
546 char *p = cfg->environmt;
547 dlg_update_start(ctrl, dlg);
548 dlg_listbox_clear(ctrl, dlg);
550 dlg_listbox_add(ctrl, dlg, p);
553 dlg_update_done(ctrl, dlg);
555 } else if (event == EVENT_ACTION) {
556 if (ctrl == ed->addbutton) {
557 char str[sizeof(cfg->environmt)];
559 dlg_editbox_get(ed->varbox, dlg, str, sizeof(str)-1);
564 p = str + strlen(str);
566 dlg_editbox_get(ed->valbox, dlg, p, sizeof(str)-1 - (p - str));
577 if ((p - cfg->environmt) + strlen(str) + 2 <
578 sizeof(cfg->environmt)) {
580 p[strlen(str) + 1] = '\0';
581 dlg_listbox_add(ed->listbox, dlg, str);
582 dlg_editbox_set(ed->varbox, dlg, "");
583 dlg_editbox_set(ed->valbox, dlg, "");
585 dlg_error_msg(dlg, "Environment too big");
587 } else if (ctrl == ed->rembutton) {
588 int i = dlg_listbox_index(ed->listbox, dlg);
594 dlg_listbox_del(ed->listbox, dlg, i);
622 struct portfwd_data {
623 union control *addbutton, *rembutton, *listbox;
624 union control *sourcebox, *destbox, *direction;
627 static void portfwd_handler(union control *ctrl, void *dlg,
628 void *data, int event)
630 Config *cfg = (Config *)data;
631 struct portfwd_data *pfd =
632 (struct portfwd_data *)ctrl->generic.context.p;
634 if (event == EVENT_REFRESH) {
635 if (ctrl == pfd->listbox) {
636 char *p = cfg->portfwd;
637 dlg_update_start(ctrl, dlg);
638 dlg_listbox_clear(ctrl, dlg);
640 dlg_listbox_add(ctrl, dlg, p);
643 dlg_update_done(ctrl, dlg);
644 } else if (ctrl == pfd->direction) {
648 dlg_radiobutton_set(ctrl, dlg, 0);
650 } else if (event == EVENT_ACTION) {
651 if (ctrl == pfd->addbutton) {
652 char str[sizeof(cfg->portfwd)];
654 int whichbutton = dlg_radiobutton_get(pfd->direction, dlg);
655 if (whichbutton == 0)
657 else if (whichbutton == 1)
661 dlg_editbox_get(pfd->sourcebox, dlg, str+1, sizeof(str) - 2);
663 dlg_error_msg(dlg, "You need to specify a source port number");
666 p = str + strlen(str);
669 dlg_editbox_get(pfd->destbox, dlg, p,
670 sizeof(str)-1 - (p - str));
671 if (!*p || !strchr(p, ':')) {
673 "You need to specify a destination address\n"
674 "in the form \"host.name:port\"");
685 if ((p - cfg->portfwd) + strlen(str) + 2 <
686 sizeof(cfg->portfwd)) {
688 p[strlen(str) + 1] = '\0';
689 dlg_listbox_add(pfd->listbox, dlg, str);
690 dlg_editbox_set(pfd->sourcebox, dlg, "");
691 dlg_editbox_set(pfd->destbox, dlg, "");
693 dlg_error_msg(dlg, "Too many forwardings");
695 } else if (ctrl == pfd->rembutton) {
696 int i = dlg_listbox_index(pfd->listbox, dlg);
702 dlg_listbox_del(pfd->listbox, dlg, i);
730 void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
731 int midsession, int protocol)
733 struct controlset *s;
734 struct sessionsaver_data *ssd;
735 struct charclass_data *ccd;
736 struct colour_data *cd;
737 struct environ_data *ed;
738 struct portfwd_data *pfd;
742 ssd = (struct sessionsaver_data *)
743 ctrl_alloc(b, sizeof(struct sessionsaver_data));
744 memset(ssd, 0, sizeof(*ssd));
745 ssd->sesslist = (midsession ? NULL : sesslist);
748 * The standard panel that appears at the bottom of all panels:
749 * Open, Cancel, Apply etc.
751 s = ctrl_getset(b, "", "", "");
752 ctrl_columns(s, 5, 20, 20, 20, 20, 20);
753 ssd->okbutton = ctrl_pushbutton(s,
754 (midsession ? "Apply" : "Open"),
755 (char)(midsession ? 'a' : 'o'),
757 sessionsaver_handler, P(ssd));
758 ssd->okbutton->button.isdefault = TRUE;
759 ssd->okbutton->generic.column = 3;
760 ssd->cancelbutton = ctrl_pushbutton(s, "Cancel", 'c', HELPCTX(no_help),
761 sessionsaver_handler, P(ssd));
762 ssd->cancelbutton->button.iscancel = TRUE;
763 ssd->cancelbutton->generic.column = 4;
764 /* We carefully don't close the 5-column part, so that platform-
765 * specific add-ons can put extra buttons alongside Open and Cancel. */
770 str = dupprintf("Basic options for your %s session", appname);
771 ctrl_settitle(b, "Session", str);
775 s = ctrl_getset(b, "Session", "hostport",
776 "Specify your connection by host name or IP address");
777 ctrl_columns(s, 2, 75, 25);
778 c = ctrl_editbox(s, "Host Name (or IP address)", 'n', 100,
779 HELPCTX(session_hostname),
780 dlg_stdeditbox_handler, I(offsetof(Config,host)),
781 I(sizeof(((Config *)0)->host)));
782 c->generic.column = 0;
783 c = ctrl_editbox(s, "Port", 'p', 100, HELPCTX(session_hostname),
784 dlg_stdeditbox_handler,
785 I(offsetof(Config,port)), I(-1));
786 c->generic.column = 1;
787 ctrl_columns(s, 1, 100);
788 if (backends[3].name == NULL) {
789 ctrl_radiobuttons(s, "Protocol:", NO_SHORTCUT, 3,
790 HELPCTX(session_hostname),
791 protocolbuttons_handler, P(c),
792 "Raw", 'r', I(PROT_RAW),
793 "Telnet", 't', I(PROT_TELNET),
794 "Rlogin", 'i', I(PROT_RLOGIN),
797 ctrl_radiobuttons(s, "Protocol:", NO_SHORTCUT, 4,
798 HELPCTX(session_hostname),
799 protocolbuttons_handler, P(c),
800 "Raw", 'r', I(PROT_RAW),
801 "Telnet", 't', I(PROT_TELNET),
802 "Rlogin", 'i', I(PROT_RLOGIN),
803 "SSH", 's', I(PROT_SSH),
807 s = ctrl_getset(b, "Session", "savedsessions",
808 "Load, save or delete a stored session");
809 ctrl_columns(s, 2, 75, 25);
810 ssd->sesslist = sesslist;
811 ssd->editbox = ctrl_editbox(s, "Saved Sessions", 'e', 100,
812 HELPCTX(session_saved),
813 sessionsaver_handler, P(ssd), P(NULL));
814 ssd->editbox->generic.column = 0;
815 /* Reset columns so that the buttons are alongside the list, rather
816 * than alongside that edit box. */
817 ctrl_columns(s, 1, 100);
818 ctrl_columns(s, 2, 75, 25);
819 ssd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
820 HELPCTX(session_saved),
821 sessionsaver_handler, P(ssd));
822 ssd->listbox->generic.column = 0;
823 ssd->listbox->listbox.height = 7;
824 ssd->loadbutton = ctrl_pushbutton(s, "Load", 'l',
825 HELPCTX(session_saved),
826 sessionsaver_handler, P(ssd));
827 ssd->loadbutton->generic.column = 1;
828 ssd->savebutton = ctrl_pushbutton(s, "Save", 'v',
829 HELPCTX(session_saved),
830 sessionsaver_handler, P(ssd));
831 ssd->savebutton->generic.column = 1;
832 ssd->delbutton = ctrl_pushbutton(s, "Delete", 'd',
833 HELPCTX(session_saved),
834 sessionsaver_handler, P(ssd));
835 ssd->delbutton->generic.column = 1;
836 ctrl_columns(s, 1, 100);
839 s = ctrl_getset(b, "Session", "otheropts", NULL);
840 c = ctrl_radiobuttons(s, "Close window on exit:", 'w', 4,
841 HELPCTX(session_coe),
842 dlg_stdradiobutton_handler,
843 I(offsetof(Config, close_on_exit)),
844 "Always", I(FORCE_ON),
845 "Never", I(FORCE_OFF),
846 "Only on clean exit", I(AUTO), NULL);
849 * The Session/Logging panel.
851 ctrl_settitle(b, "Session/Logging", "Options controlling session logging");
853 s = ctrl_getset(b, "Session/Logging", "main", NULL);
855 * The logging buttons change depending on whether SSH packet
856 * logging can sensibly be available.
860 if ((midsession && protocol == PROT_SSH) ||
861 (!midsession && backends[3].name != NULL))
862 sshlogname = "Log SSH packet data";
864 sshlogname = NULL; /* this will disable the button */
865 ctrl_radiobuttons(s, "Session logging:", NO_SHORTCUT, 1,
866 HELPCTX(logging_main),
867 dlg_stdradiobutton_handler,
868 I(offsetof(Config, logtype)),
869 "Logging turned off completely", 't', I(LGTYP_NONE),
870 "Log printable output only", 'p', I(LGTYP_ASCII),
871 "Log all session output", 'l', I(LGTYP_DEBUG),
872 sshlogname, 's', I(LGTYP_PACKETS),
875 ctrl_filesel(s, "Log file name:", 'f',
876 NULL, TRUE, "Select session log file name",
877 HELPCTX(logging_filename),
878 dlg_stdfilesel_handler, I(offsetof(Config, logfilename)));
879 ctrl_text(s, "(Log file name can contain &Y, &M, &D for date,"
880 " &T for time, and &H for host name)",
881 HELPCTX(logging_filename));
882 ctrl_radiobuttons(s, "What to do if the log file already exists:", 'e', 1,
883 HELPCTX(logging_exists),
884 dlg_stdradiobutton_handler, I(offsetof(Config,logxfovr)),
885 "Always overwrite it", I(LGXF_OVR),
886 "Always append to the end of it", I(LGXF_APN),
887 "Ask the user every time", I(LGXF_ASK), NULL);
888 ctrl_checkbox(s, "Flush log file frequently", 'u',
889 HELPCTX(logging_flush),
890 dlg_stdcheckbox_handler, I(offsetof(Config,logflush)));
892 if ((midsession && protocol == PROT_SSH) ||
893 (!midsession && backends[3].name != NULL)) {
894 s = ctrl_getset(b, "Session/Logging", "ssh",
895 "Options specific to SSH packet logging");
896 ctrl_checkbox(s, "Omit known password fields", 'k',
897 HELPCTX(logging_ssh_omit_password),
898 dlg_stdcheckbox_handler, I(offsetof(Config,logomitpass)));
899 ctrl_checkbox(s, "Omit session data", 'd',
900 HELPCTX(logging_ssh_omit_data),
901 dlg_stdcheckbox_handler, I(offsetof(Config,logomitdata)));
905 * The Terminal panel.
907 ctrl_settitle(b, "Terminal", "Options controlling the terminal emulation");
909 s = ctrl_getset(b, "Terminal", "general", "Set various terminal options");
910 ctrl_checkbox(s, "Auto wrap mode initially on", 'w',
911 HELPCTX(terminal_autowrap),
912 dlg_stdcheckbox_handler, I(offsetof(Config,wrap_mode)));
913 ctrl_checkbox(s, "DEC Origin Mode initially on", 'd',
914 HELPCTX(terminal_decom),
915 dlg_stdcheckbox_handler, I(offsetof(Config,dec_om)));
916 ctrl_checkbox(s, "Implicit CR in every LF", 'r',
917 HELPCTX(terminal_lfhascr),
918 dlg_stdcheckbox_handler, I(offsetof(Config,lfhascr)));
919 ctrl_checkbox(s, "Use background colour to erase screen", 'e',
920 HELPCTX(terminal_bce),
921 dlg_stdcheckbox_handler, I(offsetof(Config,bce)));
922 ctrl_checkbox(s, "Enable blinking text", 'n',
923 HELPCTX(terminal_blink),
924 dlg_stdcheckbox_handler, I(offsetof(Config,blinktext)));
925 ctrl_editbox(s, "Answerback to ^E:", 's', 100,
926 HELPCTX(terminal_answerback),
927 dlg_stdeditbox_handler, I(offsetof(Config,answerback)),
928 I(sizeof(((Config *)0)->answerback)));
930 s = ctrl_getset(b, "Terminal", "ldisc", "Line discipline options");
931 ctrl_radiobuttons(s, "Local echo:", 'l', 3,
932 HELPCTX(terminal_localecho),
933 dlg_stdradiobutton_handler,I(offsetof(Config,localecho)),
935 "Force on", I(FORCE_ON),
936 "Force off", I(FORCE_OFF), NULL);
937 ctrl_radiobuttons(s, "Local line editing:", 't', 3,
938 HELPCTX(terminal_localedit),
939 dlg_stdradiobutton_handler,I(offsetof(Config,localedit)),
941 "Force on", I(FORCE_ON),
942 "Force off", I(FORCE_OFF), NULL);
944 s = ctrl_getset(b, "Terminal", "printing", "Remote-controlled printing");
945 ctrl_combobox(s, "Printer to send ANSI printer output to:", 'p', 100,
946 HELPCTX(terminal_printing),
947 printerbox_handler, P(NULL), P(NULL));
950 * The Terminal/Keyboard panel.
952 ctrl_settitle(b, "Terminal/Keyboard",
953 "Options controlling the effects of keys");
955 s = ctrl_getset(b, "Terminal/Keyboard", "mappings",
956 "Change the sequences sent by:");
957 ctrl_radiobuttons(s, "The Backspace key", 'b', 2,
958 HELPCTX(keyboard_backspace),
959 dlg_stdradiobutton_handler,
960 I(offsetof(Config, bksp_is_delete)),
961 "Control-H", I(0), "Control-? (127)", I(1), NULL);
962 ctrl_radiobuttons(s, "The Home and End keys", 'e', 2,
963 HELPCTX(keyboard_homeend),
964 dlg_stdradiobutton_handler,
965 I(offsetof(Config, rxvt_homeend)),
966 "Standard", I(0), "rxvt", I(1), NULL);
967 ctrl_radiobuttons(s, "The Function keys and keypad", 'f', 3,
968 HELPCTX(keyboard_funkeys),
969 dlg_stdradiobutton_handler,
970 I(offsetof(Config, funky_type)),
971 "ESC[n~", I(0), "Linux", I(1), "Xterm R6", I(2),
972 "VT400", I(3), "VT100+", I(4), "SCO", I(5), NULL);
974 s = ctrl_getset(b, "Terminal/Keyboard", "appkeypad",
975 "Application keypad settings:");
976 ctrl_radiobuttons(s, "Initial state of cursor keys:", 'r', 3,
977 HELPCTX(keyboard_appcursor),
978 dlg_stdradiobutton_handler,
979 I(offsetof(Config, app_cursor)),
980 "Normal", I(0), "Application", I(1), NULL);
981 ctrl_radiobuttons(s, "Initial state of numeric keypad:", 'n', 3,
982 HELPCTX(keyboard_appkeypad),
983 numeric_keypad_handler, P(NULL),
984 "Normal", I(0), "Application", I(1), "NetHack", I(2),
988 * The Terminal/Bell panel.
990 ctrl_settitle(b, "Terminal/Bell",
991 "Options controlling the terminal bell");
993 s = ctrl_getset(b, "Terminal/Bell", "style", "Set the style of bell");
994 ctrl_radiobuttons(s, "Action to happen when a bell occurs:", 'b', 1,
996 dlg_stdradiobutton_handler, I(offsetof(Config, beep)),
997 "None (bell disabled)", I(BELL_DISABLED),
998 "Make default system alert sound", I(BELL_DEFAULT),
999 "Visual bell (flash window)", I(BELL_VISUAL), NULL);
1001 s = ctrl_getset(b, "Terminal/Bell", "overload",
1002 "Control the bell overload behaviour");
1003 ctrl_checkbox(s, "Bell is temporarily disabled when over-used", 'd',
1004 HELPCTX(bell_overload),
1005 dlg_stdcheckbox_handler, I(offsetof(Config,bellovl)));
1006 ctrl_editbox(s, "Over-use means this many bells...", 'm', 20,
1007 HELPCTX(bell_overload),
1008 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_n)), I(-1));
1009 ctrl_editbox(s, "... in this many seconds", 't', 20,
1010 HELPCTX(bell_overload),
1011 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_t)),
1013 ctrl_text(s, "The bell is re-enabled after a few seconds of silence.",
1014 HELPCTX(bell_overload));
1015 ctrl_editbox(s, "Seconds of silence required", 's', 20,
1016 HELPCTX(bell_overload),
1017 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_s)),
1021 * The Terminal/Features panel.
1023 ctrl_settitle(b, "Terminal/Features",
1024 "Enabling and disabling advanced terminal features");
1026 s = ctrl_getset(b, "Terminal/Features", "main", NULL);
1027 ctrl_checkbox(s, "Disable application cursor keys mode", 'u',
1028 HELPCTX(features_application),
1029 dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_c)));
1030 ctrl_checkbox(s, "Disable application keypad mode", 'k',
1031 HELPCTX(features_application),
1032 dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_k)));
1033 ctrl_checkbox(s, "Disable xterm-style mouse reporting", 'x',
1034 HELPCTX(features_mouse),
1035 dlg_stdcheckbox_handler, I(offsetof(Config,no_mouse_rep)));
1036 ctrl_checkbox(s, "Disable remote-controlled terminal resizing", 's',
1037 HELPCTX(features_resize),
1038 dlg_stdcheckbox_handler,
1039 I(offsetof(Config,no_remote_resize)));
1040 ctrl_checkbox(s, "Disable switching to alternate terminal screen", 'w',
1041 HELPCTX(features_altscreen),
1042 dlg_stdcheckbox_handler, I(offsetof(Config,no_alt_screen)));
1043 ctrl_checkbox(s, "Disable remote-controlled window title changing", 't',
1044 HELPCTX(features_retitle),
1045 dlg_stdcheckbox_handler,
1046 I(offsetof(Config,no_remote_wintitle)));
1047 ctrl_checkbox(s, "Disable remote window title querying (SECURITY)",
1048 'q', HELPCTX(features_qtitle), dlg_stdcheckbox_handler,
1049 I(offsetof(Config,no_remote_qtitle)));
1050 ctrl_checkbox(s, "Disable destructive backspace on server sending ^?",'b',
1051 HELPCTX(features_dbackspace),
1052 dlg_stdcheckbox_handler, I(offsetof(Config,no_dbackspace)));
1053 ctrl_checkbox(s, "Disable remote-controlled character set configuration",
1054 'r', HELPCTX(features_charset), dlg_stdcheckbox_handler,
1055 I(offsetof(Config,no_remote_charset)));
1056 ctrl_checkbox(s, "Disable Arabic text shaping",
1057 'l', HELPCTX(features_arabicshaping), dlg_stdcheckbox_handler,
1058 I(offsetof(Config, arabicshaping)));
1059 ctrl_checkbox(s, "Disable bidirectional text display",
1060 'd', HELPCTX(features_bidi), dlg_stdcheckbox_handler,
1061 I(offsetof(Config, bidi)));
1066 str = dupprintf("Options controlling %s's window", appname);
1067 ctrl_settitle(b, "Window", str);
1070 s = ctrl_getset(b, "Window", "size", "Set the size of the window");
1071 ctrl_columns(s, 2, 50, 50);
1072 c = ctrl_editbox(s, "Rows", 'r', 100,
1073 HELPCTX(window_size),
1074 dlg_stdeditbox_handler, I(offsetof(Config,height)),I(-1));
1075 c->generic.column = 0;
1076 c = ctrl_editbox(s, "Columns", 'm', 100,
1077 HELPCTX(window_size),
1078 dlg_stdeditbox_handler, I(offsetof(Config,width)), I(-1));
1079 c->generic.column = 1;
1080 ctrl_columns(s, 1, 100);
1082 s = ctrl_getset(b, "Window", "scrollback",
1083 "Control the scrollback in the window");
1084 ctrl_editbox(s, "Lines of scrollback", 's', 50,
1085 HELPCTX(window_scrollback),
1086 dlg_stdeditbox_handler, I(offsetof(Config,savelines)), I(-1));
1087 ctrl_checkbox(s, "Display scrollbar", 'd',
1088 HELPCTX(window_scrollback),
1089 dlg_stdcheckbox_handler, I(offsetof(Config,scrollbar)));
1090 ctrl_checkbox(s, "Reset scrollback on keypress", 'k',
1091 HELPCTX(window_scrollback),
1092 dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_key)));
1093 ctrl_checkbox(s, "Reset scrollback on display activity", 'p',
1094 HELPCTX(window_scrollback),
1095 dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_disp)));
1096 ctrl_checkbox(s, "Push erased text into scrollback", 'e',
1097 HELPCTX(window_erased),
1098 dlg_stdcheckbox_handler,
1099 I(offsetof(Config,erase_to_scrollback)));
1102 * The Window/Appearance panel.
1104 str = dupprintf("Configure the appearance of %s's window", appname);
1105 ctrl_settitle(b, "Window/Appearance", str);
1108 s = ctrl_getset(b, "Window/Appearance", "cursor",
1109 "Adjust the use of the cursor");
1110 ctrl_radiobuttons(s, "Cursor appearance:", NO_SHORTCUT, 3,
1111 HELPCTX(appearance_cursor),
1112 dlg_stdradiobutton_handler,
1113 I(offsetof(Config, cursor_type)),
1115 "Underline", 'u', I(1),
1116 "Vertical line", 'v', I(2), NULL);
1117 ctrl_checkbox(s, "Cursor blinks", 'b',
1118 HELPCTX(appearance_cursor),
1119 dlg_stdcheckbox_handler, I(offsetof(Config,blink_cur)));
1121 s = ctrl_getset(b, "Window/Appearance", "font",
1123 ctrl_fontsel(s, "Font used in the terminal window", 'n',
1124 HELPCTX(appearance_font),
1125 dlg_stdfontsel_handler, I(offsetof(Config, font)));
1127 s = ctrl_getset(b, "Window/Appearance", "mouse",
1128 "Adjust the use of the mouse pointer");
1129 ctrl_checkbox(s, "Hide mouse pointer when typing in window", 'p',
1130 HELPCTX(appearance_hidemouse),
1131 dlg_stdcheckbox_handler, I(offsetof(Config,hide_mouseptr)));
1133 s = ctrl_getset(b, "Window/Appearance", "border",
1134 "Adjust the window border");
1135 ctrl_editbox(s, "Gap between text and window edge:", NO_SHORTCUT, 20,
1136 HELPCTX(appearance_border),
1137 dlg_stdeditbox_handler,
1138 I(offsetof(Config,window_border)), I(-1));
1141 * The Window/Behaviour panel.
1143 str = dupprintf("Configure the behaviour of %s's window", appname);
1144 ctrl_settitle(b, "Window/Behaviour", str);
1147 s = ctrl_getset(b, "Window/Behaviour", "title",
1148 "Adjust the behaviour of the window title");
1149 ctrl_editbox(s, "Window title:", 't', 100,
1150 HELPCTX(appearance_title),
1151 dlg_stdeditbox_handler, I(offsetof(Config,wintitle)),
1152 I(sizeof(((Config *)0)->wintitle)));
1153 ctrl_checkbox(s, "Separate window and icon titles", 'i',
1154 HELPCTX(appearance_title),
1155 dlg_stdcheckbox_handler,
1156 I(CHECKBOX_INVERT | offsetof(Config,win_name_always)));
1158 s = ctrl_getset(b, "Window/Behaviour", "main", NULL);
1159 ctrl_checkbox(s, "Warn before closing window", 'w',
1160 HELPCTX(behaviour_closewarn),
1161 dlg_stdcheckbox_handler, I(offsetof(Config,warn_on_close)));
1164 * The Window/Translation panel.
1166 ctrl_settitle(b, "Window/Translation",
1167 "Options controlling character set translation");
1169 s = ctrl_getset(b, "Window/Translation", "trans",
1170 "Character set translation on received data");
1171 ctrl_combobox(s, "Received data assumed to be in which character set:",
1172 'r', 100, HELPCTX(translation_codepage),
1173 codepage_handler, P(NULL), P(NULL));
1175 str = dupprintf("Adjust how %s handles line drawing characters", appname);
1176 s = ctrl_getset(b, "Window/Translation", "linedraw", str);
1178 ctrl_radiobuttons(s, "Handling of line drawing characters:", NO_SHORTCUT,1,
1179 HELPCTX(translation_linedraw),
1180 dlg_stdradiobutton_handler,
1181 I(offsetof(Config, vtmode)),
1182 "Use Unicode line drawing code points",'u',I(VT_UNICODE),
1183 "Poor man's line drawing (+, - and |)",'p',I(VT_POORMAN),
1185 ctrl_checkbox(s, "Copy and paste line drawing characters as lqqqk",'d',
1186 HELPCTX(selection_linedraw),
1187 dlg_stdcheckbox_handler, I(offsetof(Config,rawcnp)));
1190 * The Window/Selection panel.
1192 ctrl_settitle(b, "Window/Selection", "Options controlling copy and paste");
1194 s = ctrl_getset(b, "Window/Selection", "mouse",
1195 "Control use of mouse");
1196 ctrl_checkbox(s, "Shift overrides application's use of mouse", 'p',
1197 HELPCTX(selection_shiftdrag),
1198 dlg_stdcheckbox_handler, I(offsetof(Config,mouse_override)));
1199 ctrl_radiobuttons(s,
1200 "Default selection mode (Alt+drag does the other one):",
1202 HELPCTX(selection_rect),
1203 dlg_stdradiobutton_handler,
1204 I(offsetof(Config, rect_select)),
1205 "Normal", 'n', I(0),
1206 "Rectangular block", 'r', I(1), NULL);
1208 s = ctrl_getset(b, "Window/Selection", "charclass",
1209 "Control the select-one-word-at-a-time mode");
1210 ccd = (struct charclass_data *)
1211 ctrl_alloc(b, sizeof(struct charclass_data));
1212 ccd->listbox = ctrl_listbox(s, "Character classes:", 'e',
1213 HELPCTX(selection_charclasses),
1214 charclass_handler, P(ccd));
1215 ccd->listbox->listbox.multisel = 1;
1216 ccd->listbox->listbox.ncols = 4;
1217 ccd->listbox->listbox.percentages = snewn(4, int);
1218 ccd->listbox->listbox.percentages[0] = 15;
1219 ccd->listbox->listbox.percentages[1] = 25;
1220 ccd->listbox->listbox.percentages[2] = 20;
1221 ccd->listbox->listbox.percentages[3] = 40;
1222 ctrl_columns(s, 2, 67, 33);
1223 ccd->editbox = ctrl_editbox(s, "Set to class", 't', 50,
1224 HELPCTX(selection_charclasses),
1225 charclass_handler, P(ccd), P(NULL));
1226 ccd->editbox->generic.column = 0;
1227 ccd->button = ctrl_pushbutton(s, "Set", 's',
1228 HELPCTX(selection_charclasses),
1229 charclass_handler, P(ccd));
1230 ccd->button->generic.column = 1;
1231 ctrl_columns(s, 1, 100);
1234 * The Window/Colours panel.
1236 ctrl_settitle(b, "Window/Colours", "Options controlling use of colours");
1238 s = ctrl_getset(b, "Window/Colours", "general",
1239 "General options for colour usage");
1240 ctrl_checkbox(s, "Allow terminal to specify ANSI colours", 'i',
1241 HELPCTX(colours_ansi),
1242 dlg_stdcheckbox_handler, I(offsetof(Config,ansi_colour)));
1243 ctrl_checkbox(s, "Allow terminal to use xterm 256-colour mode", '2',
1244 HELPCTX(colours_xterm256), dlg_stdcheckbox_handler,
1245 I(offsetof(Config,xterm_256_colour)));
1246 ctrl_checkbox(s, "Bolded text is a different colour", 'b',
1247 HELPCTX(colours_bold),
1248 dlg_stdcheckbox_handler, I(offsetof(Config,bold_colour)));
1250 str = dupprintf("Adjust the precise colours %s displays", appname);
1251 s = ctrl_getset(b, "Window/Colours", "adjust", str);
1253 ctrl_text(s, "Select a colour from the list, and then click the"
1254 " Modify button to change its appearance.",
1255 HELPCTX(colours_config));
1256 ctrl_columns(s, 2, 67, 33);
1257 cd = (struct colour_data *)ctrl_alloc(b, sizeof(struct colour_data));
1258 cd->listbox = ctrl_listbox(s, "Select a colour to adjust:", 'u',
1259 HELPCTX(colours_config), colour_handler, P(cd));
1260 cd->listbox->generic.column = 0;
1261 cd->listbox->listbox.height = 7;
1262 c = ctrl_text(s, "RGB value:", HELPCTX(colours_config));
1263 c->generic.column = 1;
1264 cd->redit = ctrl_editbox(s, "Red", 'r', 50, HELPCTX(colours_config),
1265 colour_handler, P(cd), P(NULL));
1266 cd->redit->generic.column = 1;
1267 cd->gedit = ctrl_editbox(s, "Green", 'n', 50, HELPCTX(colours_config),
1268 colour_handler, P(cd), P(NULL));
1269 cd->gedit->generic.column = 1;
1270 cd->bedit = ctrl_editbox(s, "Blue", 'e', 50, HELPCTX(colours_config),
1271 colour_handler, P(cd), P(NULL));
1272 cd->bedit->generic.column = 1;
1273 cd->button = ctrl_pushbutton(s, "Modify", 'm', HELPCTX(colours_config),
1274 colour_handler, P(cd));
1275 cd->button->generic.column = 1;
1276 ctrl_columns(s, 1, 100);
1279 * The Connection panel. This doesn't show up if we're in a
1280 * non-network utility such as pterm. We tell this by being
1281 * passed a protocol < 0.
1283 if (protocol >= 0) {
1284 ctrl_settitle(b, "Connection", "Options controlling the connection");
1287 s = ctrl_getset(b, "Connection", "data",
1288 "Data to send to the server");
1289 ctrl_editbox(s, "Terminal-type string", 't', 50,
1290 HELPCTX(connection_termtype),
1291 dlg_stdeditbox_handler, I(offsetof(Config,termtype)),
1292 I(sizeof(((Config *)0)->termtype)));
1293 ctrl_editbox(s, "Terminal speeds", 's', 50,
1294 HELPCTX(connection_termspeed),
1295 dlg_stdeditbox_handler, I(offsetof(Config,termspeed)),
1296 I(sizeof(((Config *)0)->termspeed)));
1297 ctrl_editbox(s, "Auto-login username", 'u', 50,
1298 HELPCTX(connection_username),
1299 dlg_stdeditbox_handler, I(offsetof(Config,username)),
1300 I(sizeof(((Config *)0)->username)));
1302 ctrl_text(s, "Environment variables:", HELPCTX(telnet_environ));
1303 ctrl_columns(s, 2, 80, 20);
1304 ed = (struct environ_data *)
1305 ctrl_alloc(b, sizeof(struct environ_data));
1306 ed->varbox = ctrl_editbox(s, "Variable", 'v', 60,
1307 HELPCTX(telnet_environ),
1308 environ_handler, P(ed), P(NULL));
1309 ed->varbox->generic.column = 0;
1310 ed->valbox = ctrl_editbox(s, "Value", 'l', 60,
1311 HELPCTX(telnet_environ),
1312 environ_handler, P(ed), P(NULL));
1313 ed->valbox->generic.column = 0;
1314 ed->addbutton = ctrl_pushbutton(s, "Add", 'd',
1315 HELPCTX(telnet_environ),
1316 environ_handler, P(ed));
1317 ed->addbutton->generic.column = 1;
1318 ed->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1319 HELPCTX(telnet_environ),
1320 environ_handler, P(ed));
1321 ed->rembutton->generic.column = 1;
1322 ctrl_columns(s, 1, 100);
1323 ed->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1324 HELPCTX(telnet_environ),
1325 environ_handler, P(ed));
1326 ed->listbox->listbox.height = 3;
1327 ed->listbox->listbox.ncols = 2;
1328 ed->listbox->listbox.percentages = snewn(2, int);
1329 ed->listbox->listbox.percentages[0] = 30;
1330 ed->listbox->listbox.percentages[1] = 70;
1333 s = ctrl_getset(b, "Connection", "keepalive",
1334 "Sending of null packets to keep session active");
1335 ctrl_editbox(s, "Seconds between keepalives (0 to turn off)", 'k', 20,
1336 HELPCTX(connection_keepalive),
1337 dlg_stdeditbox_handler, I(offsetof(Config,ping_interval)),
1341 s = ctrl_getset(b, "Connection", "tcp",
1342 "Low-level TCP connection options");
1343 ctrl_checkbox(s, "Disable Nagle's algorithm (TCP_NODELAY option)",
1344 'n', HELPCTX(connection_nodelay),
1345 dlg_stdcheckbox_handler,
1346 I(offsetof(Config,tcp_nodelay)));
1347 ctrl_checkbox(s, "Enable TCP keepalives (SO_KEEPALIVE option)",
1348 'p', HELPCTX(connection_tcpkeepalive),
1349 dlg_stdcheckbox_handler,
1350 I(offsetof(Config,tcp_keepalives)));
1357 * The Connection/Proxy panel.
1359 ctrl_settitle(b, "Connection/Proxy",
1360 "Options controlling proxy usage");
1362 s = ctrl_getset(b, "Connection/Proxy", "basics", NULL);
1363 ctrl_radiobuttons(s, "Proxy type:", 't', 3,
1364 HELPCTX(proxy_type),
1365 dlg_stdradiobutton_handler,
1366 I(offsetof(Config, proxy_type)),
1367 "None", I(PROXY_NONE),
1368 "SOCKS 4", I(PROXY_SOCKS4),
1369 "SOCKS 5", I(PROXY_SOCKS5),
1370 "HTTP", I(PROXY_HTTP),
1371 "Telnet", I(PROXY_TELNET),
1373 ctrl_columns(s, 2, 80, 20);
1374 c = ctrl_editbox(s, "Proxy hostname", 'y', 100,
1375 HELPCTX(proxy_main),
1376 dlg_stdeditbox_handler,
1377 I(offsetof(Config,proxy_host)),
1378 I(sizeof(((Config *)0)->proxy_host)));
1379 c->generic.column = 0;
1380 c = ctrl_editbox(s, "Port", 'p', 100,
1381 HELPCTX(proxy_main),
1382 dlg_stdeditbox_handler,
1383 I(offsetof(Config,proxy_port)),
1385 c->generic.column = 1;
1386 ctrl_columns(s, 1, 100);
1387 ctrl_editbox(s, "Exclude Hosts/IPs", 'e', 100,
1388 HELPCTX(proxy_exclude),
1389 dlg_stdeditbox_handler,
1390 I(offsetof(Config,proxy_exclude_list)),
1391 I(sizeof(((Config *)0)->proxy_exclude_list)));
1392 ctrl_checkbox(s, "Consider proxying local host connections", 'x',
1393 HELPCTX(proxy_exclude),
1394 dlg_stdcheckbox_handler,
1395 I(offsetof(Config,even_proxy_localhost)));
1396 ctrl_radiobuttons(s, "Do DNS name lookup at proxy end:", 'd', 3,
1398 dlg_stdradiobutton_handler,
1399 I(offsetof(Config, proxy_dns)),
1402 "Yes", I(FORCE_ON), NULL);
1403 ctrl_editbox(s, "Username", 'u', 60,
1404 HELPCTX(proxy_auth),
1405 dlg_stdeditbox_handler,
1406 I(offsetof(Config,proxy_username)),
1407 I(sizeof(((Config *)0)->proxy_username)));
1408 c = ctrl_editbox(s, "Password", 'w', 60,
1409 HELPCTX(proxy_auth),
1410 dlg_stdeditbox_handler,
1411 I(offsetof(Config,proxy_password)),
1412 I(sizeof(((Config *)0)->proxy_password)));
1413 c->editbox.password = 1;
1414 ctrl_editbox(s, "Telnet command", 'm', 100,
1415 HELPCTX(proxy_command),
1416 dlg_stdeditbox_handler,
1417 I(offsetof(Config,proxy_telnet_command)),
1418 I(sizeof(((Config *)0)->proxy_telnet_command)));
1422 * The Telnet panel exists in the base config box, and in a
1423 * mid-session reconfig box _if_ we're using Telnet.
1425 if (!midsession || protocol == PROT_TELNET) {
1427 * The Connection/Telnet panel.
1429 ctrl_settitle(b, "Connection/Telnet",
1430 "Options controlling Telnet connections");
1432 s = ctrl_getset(b, "Connection/Telnet", "protocol",
1433 "Telnet protocol adjustments");
1436 ctrl_radiobuttons(s, "Handling of OLD_ENVIRON ambiguity:",
1438 HELPCTX(telnet_oldenviron),
1439 dlg_stdradiobutton_handler,
1440 I(offsetof(Config, rfc_environ)),
1441 "BSD (commonplace)", 'b', I(0),
1442 "RFC 1408 (unusual)", 'f', I(1), NULL);
1443 ctrl_radiobuttons(s, "Telnet negotiation mode:", 't', 2,
1444 HELPCTX(telnet_passive),
1445 dlg_stdradiobutton_handler,
1446 I(offsetof(Config, passive_telnet)),
1447 "Passive", I(1), "Active", I(0), NULL);
1449 ctrl_checkbox(s, "Keyboard sends Telnet special commands", 'k',
1450 HELPCTX(telnet_specialkeys),
1451 dlg_stdcheckbox_handler,
1452 I(offsetof(Config,telnet_keyboard)));
1453 ctrl_checkbox(s, "Return key sends Telnet New Line instead of ^M",
1454 'm', HELPCTX(telnet_newline),
1455 dlg_stdcheckbox_handler,
1456 I(offsetof(Config,telnet_newline)));
1462 * The Connection/Rlogin panel.
1464 ctrl_settitle(b, "Connection/Rlogin",
1465 "Options controlling Rlogin connections");
1467 s = ctrl_getset(b, "Connection/Rlogin", "data",
1468 "Data to send to the server");
1469 ctrl_editbox(s, "Local username:", 'l', 50,
1470 HELPCTX(rlogin_localuser),
1471 dlg_stdeditbox_handler, I(offsetof(Config,localusername)),
1472 I(sizeof(((Config *)0)->localusername)));
1477 * All the SSH stuff is omitted in PuTTYtel.
1480 if (!midsession && backends[3].name != NULL) {
1483 * The Connection/SSH panel.
1485 ctrl_settitle(b, "Connection/SSH",
1486 "Options controlling SSH connections");
1488 s = ctrl_getset(b, "Connection/SSH", "data",
1489 "Data to send to the server");
1490 ctrl_editbox(s, "Remote command:", 'r', 100,
1491 HELPCTX(ssh_command),
1492 dlg_stdeditbox_handler, I(offsetof(Config,remote_cmd)),
1493 I(sizeof(((Config *)0)->remote_cmd)));
1495 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1496 ctrl_checkbox(s, "Don't allocate a pseudo-terminal", 'p',
1498 dlg_stdcheckbox_handler,
1499 I(offsetof(Config,nopty)));
1500 ctrl_checkbox(s, "Don't start a shell or command at all", 'n',
1501 HELPCTX(ssh_noshell),
1502 dlg_stdcheckbox_handler,
1503 I(offsetof(Config,ssh_no_shell)));
1504 ctrl_checkbox(s, "Enable compression", 'e',
1505 HELPCTX(ssh_compress),
1506 dlg_stdcheckbox_handler,
1507 I(offsetof(Config,compression)));
1508 ctrl_radiobuttons(s, "Preferred SSH protocol version:", NO_SHORTCUT, 4,
1509 HELPCTX(ssh_protocol),
1510 dlg_stdradiobutton_handler,
1511 I(offsetof(Config, sshprot)),
1512 "1 only", 'l', I(0),
1515 "2 only", 'y', I(3), NULL);
1517 s = ctrl_getset(b, "Connection/SSH", "encryption", "Encryption options");
1518 c = ctrl_draglist(s, "Encryption cipher selection policy:", 's',
1519 HELPCTX(ssh_ciphers),
1520 cipherlist_handler, P(NULL));
1521 c->listbox.height = 6;
1523 ctrl_checkbox(s, "Enable legacy use of single-DES in SSH 2", 'i',
1524 HELPCTX(ssh_ciphers),
1525 dlg_stdcheckbox_handler,
1526 I(offsetof(Config,ssh2_des_cbc)));
1529 * The Connection/SSH/Auth panel.
1531 ctrl_settitle(b, "Connection/SSH/Auth",
1532 "Options controlling SSH authentication");
1534 s = ctrl_getset(b, "Connection/SSH/Auth", "methods",
1535 "Authentication methods");
1536 ctrl_checkbox(s, "Attempt TIS or CryptoCard auth (SSH1)", 'm',
1537 HELPCTX(ssh_auth_tis),
1538 dlg_stdcheckbox_handler,
1539 I(offsetof(Config,try_tis_auth)));
1540 ctrl_checkbox(s, "Attempt \"keyboard-interactive\" auth (SSH2)",
1541 'i', HELPCTX(ssh_auth_ki),
1542 dlg_stdcheckbox_handler,
1543 I(offsetof(Config,try_ki_auth)));
1545 s = ctrl_getset(b, "Connection/SSH/Auth", "params",
1546 "Authentication parameters");
1547 ctrl_checkbox(s, "Allow agent forwarding", 'f',
1548 HELPCTX(ssh_auth_agentfwd),
1549 dlg_stdcheckbox_handler, I(offsetof(Config,agentfwd)));
1550 ctrl_checkbox(s, "Allow attempted changes of username in SSH2", 'u',
1551 HELPCTX(ssh_auth_changeuser),
1552 dlg_stdcheckbox_handler,
1553 I(offsetof(Config,change_username)));
1554 ctrl_filesel(s, "Private key file for authentication:", 'k',
1555 FILTER_KEY_FILES, FALSE, "Select private key file",
1556 HELPCTX(ssh_auth_privkey),
1557 dlg_stdfilesel_handler, I(offsetof(Config, keyfile)));
1560 * The Connection/SSH/Tunnels panel.
1562 ctrl_settitle(b, "Connection/SSH/Tunnels",
1563 "Options controlling SSH tunnelling");
1565 s = ctrl_getset(b, "Connection/SSH/Tunnels", "x11", "X11 forwarding");
1566 ctrl_checkbox(s, "Enable X11 forwarding", 'e',
1567 HELPCTX(ssh_tunnels_x11),
1568 dlg_stdcheckbox_handler,I(offsetof(Config,x11_forward)));
1569 ctrl_editbox(s, "X display location", 'x', 50,
1570 HELPCTX(ssh_tunnels_x11),
1571 dlg_stdeditbox_handler, I(offsetof(Config,x11_display)),
1572 I(sizeof(((Config *)0)->x11_display)));
1573 ctrl_radiobuttons(s, "Remote X11 authentication protocol", 'u', 2,
1574 HELPCTX(ssh_tunnels_x11auth),
1575 dlg_stdradiobutton_handler,
1576 I(offsetof(Config, x11_auth)),
1577 "MIT-Magic-Cookie-1", I(X11_MIT),
1578 "XDM-Authorization-1", I(X11_XDM), NULL);
1580 s = ctrl_getset(b, "Connection/SSH/Tunnels", "portfwd",
1582 ctrl_checkbox(s, "Local ports accept connections from other hosts",'t',
1583 HELPCTX(ssh_tunnels_portfwd_localhost),
1584 dlg_stdcheckbox_handler,
1585 I(offsetof(Config,lport_acceptall)));
1586 ctrl_checkbox(s, "Remote ports do the same (SSH v2 only)", 'p',
1587 HELPCTX(ssh_tunnels_portfwd_localhost),
1588 dlg_stdcheckbox_handler,
1589 I(offsetof(Config,rport_acceptall)));
1591 ctrl_columns(s, 3, 55, 20, 25);
1592 c = ctrl_text(s, "Forwarded ports:", HELPCTX(ssh_tunnels_portfwd));
1593 c->generic.column = COLUMN_FIELD(0,2);
1594 /* You want to select from the list, _then_ hit Remove. So tab order
1595 * should be that way round. */
1596 pfd = (struct portfwd_data *)ctrl_alloc(b,sizeof(struct portfwd_data));
1597 pfd->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1598 HELPCTX(ssh_tunnels_portfwd),
1599 portfwd_handler, P(pfd));
1600 pfd->rembutton->generic.column = 2;
1601 pfd->rembutton->generic.tabdelay = 1;
1602 pfd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1603 HELPCTX(ssh_tunnels_portfwd),
1604 portfwd_handler, P(pfd));
1605 pfd->listbox->listbox.height = 3;
1606 pfd->listbox->listbox.ncols = 2;
1607 pfd->listbox->listbox.percentages = snewn(2, int);
1608 pfd->listbox->listbox.percentages[0] = 20;
1609 pfd->listbox->listbox.percentages[1] = 80;
1610 ctrl_tabdelay(s, pfd->rembutton);
1611 ctrl_text(s, "Add new forwarded port:", HELPCTX(ssh_tunnels_portfwd));
1612 /* You want to enter source, destination and type, _then_ hit Add.
1613 * Again, we adjust the tab order to reflect this. */
1614 pfd->addbutton = ctrl_pushbutton(s, "Add", 'd',
1615 HELPCTX(ssh_tunnels_portfwd),
1616 portfwd_handler, P(pfd));
1617 pfd->addbutton->generic.column = 2;
1618 pfd->addbutton->generic.tabdelay = 1;
1619 pfd->sourcebox = ctrl_editbox(s, "Source port", 's', 40,
1620 HELPCTX(ssh_tunnels_portfwd),
1621 portfwd_handler, P(pfd), P(NULL));
1622 pfd->sourcebox->generic.column = 0;
1623 pfd->destbox = ctrl_editbox(s, "Destination", 'i', 67,
1624 HELPCTX(ssh_tunnels_portfwd),
1625 portfwd_handler, P(pfd), P(NULL));
1626 pfd->direction = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
1627 HELPCTX(ssh_tunnels_portfwd),
1628 portfwd_handler, P(pfd),
1629 "Local", 'l', P(NULL),
1630 "Remote", 'm', P(NULL),
1631 "Dynamic", 'y', P(NULL),
1633 ctrl_tabdelay(s, pfd->addbutton);
1634 ctrl_columns(s, 1, 100);
1637 * The Connection/SSH/Bugs panel.
1639 ctrl_settitle(b, "Connection/SSH/Bugs",
1640 "Workarounds for SSH server bugs");
1642 s = ctrl_getset(b, "Connection/SSH/Bugs", "main",
1643 "Detection of known bugs in SSH servers");
1644 ctrl_droplist(s, "Chokes on SSH1 ignore messages", 'i', 20,
1645 HELPCTX(ssh_bugs_ignore1),
1646 sshbug_handler, I(offsetof(Config,sshbug_ignore1)));
1647 ctrl_droplist(s, "Refuses all SSH1 password camouflage", 's', 20,
1648 HELPCTX(ssh_bugs_plainpw1),
1649 sshbug_handler, I(offsetof(Config,sshbug_plainpw1)));
1650 ctrl_droplist(s, "Chokes on SSH1 RSA authentication", 'r', 20,
1651 HELPCTX(ssh_bugs_rsa1),
1652 sshbug_handler, I(offsetof(Config,sshbug_rsa1)));
1653 ctrl_droplist(s, "Miscomputes SSH2 HMAC keys", 'm', 20,
1654 HELPCTX(ssh_bugs_hmac2),
1655 sshbug_handler, I(offsetof(Config,sshbug_hmac2)));
1656 ctrl_droplist(s, "Miscomputes SSH2 encryption keys", 'e', 20,
1657 HELPCTX(ssh_bugs_derivekey2),
1658 sshbug_handler, I(offsetof(Config,sshbug_derivekey2)));
1659 ctrl_droplist(s, "Requires padding on SSH2 RSA signatures", 'p', 20,
1660 HELPCTX(ssh_bugs_rsapad2),
1661 sshbug_handler, I(offsetof(Config,sshbug_rsapad2)));
1662 ctrl_droplist(s, "Chokes on Diffie-Hellman group exchange", 'd', 20,
1663 HELPCTX(ssh_bugs_dhgex2),
1664 sshbug_handler, I(offsetof(Config,sshbug_dhgex2)));
1665 ctrl_droplist(s, "Misuses the session ID in PK auth", 'n', 20,
1666 HELPCTX(ssh_bugs_pksessid2),
1667 sshbug_handler, I(offsetof(Config,sshbug_pksessid2)));