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 */
367 * Otherwise, do the normal thing: if we have a valid
368 * session, get going.
374 } else if (ctrl == ssd->cancelbutton) {
380 struct charclass_data {
381 union control *listbox, *editbox, *button;
384 static void charclass_handler(union control *ctrl, void *dlg,
385 void *data, int event)
387 Config *cfg = (Config *)data;
388 struct charclass_data *ccd =
389 (struct charclass_data *)ctrl->generic.context.p;
391 if (event == EVENT_REFRESH) {
392 if (ctrl == ccd->listbox) {
394 dlg_update_start(ctrl, dlg);
395 dlg_listbox_clear(ctrl, dlg);
396 for (i = 0; i < 128; i++) {
398 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
399 (i >= 0x21 && i != 0x7F) ? i : ' ', cfg->wordness[i]);
400 dlg_listbox_add(ctrl, dlg, str);
402 dlg_update_done(ctrl, dlg);
404 } else if (event == EVENT_ACTION) {
405 if (ctrl == ccd->button) {
408 dlg_editbox_get(ccd->editbox, dlg, str, sizeof(str));
410 for (i = 0; i < 128; i++) {
411 if (dlg_listbox_issel(ccd->listbox, dlg, i))
412 cfg->wordness[i] = n;
414 dlg_refresh(ccd->listbox, dlg);
420 union control *listbox, *redit, *gedit, *bedit, *button;
423 static const char *const colours[] = {
424 "Default Foreground", "Default Bold Foreground",
425 "Default Background", "Default Bold Background",
426 "Cursor Text", "Cursor Colour",
427 "ANSI Black", "ANSI Black Bold",
428 "ANSI Red", "ANSI Red Bold",
429 "ANSI Green", "ANSI Green Bold",
430 "ANSI Yellow", "ANSI Yellow Bold",
431 "ANSI Blue", "ANSI Blue Bold",
432 "ANSI Magenta", "ANSI Magenta Bold",
433 "ANSI Cyan", "ANSI Cyan Bold",
434 "ANSI White", "ANSI White Bold"
437 static void colour_handler(union control *ctrl, void *dlg,
438 void *data, int event)
440 Config *cfg = (Config *)data;
441 struct colour_data *cd =
442 (struct colour_data *)ctrl->generic.context.p;
443 int update = FALSE, r, g, b;
445 if (event == EVENT_REFRESH) {
446 if (ctrl == cd->listbox) {
448 dlg_update_start(ctrl, dlg);
449 dlg_listbox_clear(ctrl, dlg);
450 for (i = 0; i < lenof(colours); i++)
451 dlg_listbox_add(ctrl, dlg, colours[i]);
452 dlg_update_done(ctrl, dlg);
453 dlg_editbox_set(cd->redit, dlg, "");
454 dlg_editbox_set(cd->gedit, dlg, "");
455 dlg_editbox_set(cd->bedit, dlg, "");
457 } else if (event == EVENT_SELCHANGE) {
458 if (ctrl == cd->listbox) {
459 /* The user has selected a colour. Update the RGB text. */
460 int i = dlg_listbox_index(ctrl, dlg);
465 r = cfg->colours[i][0];
466 g = cfg->colours[i][1];
467 b = cfg->colours[i][2];
470 } else if (event == EVENT_VALCHANGE) {
471 if (ctrl == cd->redit || ctrl == cd->gedit || ctrl == cd->bedit) {
472 /* The user has changed the colour using the edit boxes. */
476 dlg_editbox_get(ctrl, dlg, buf, lenof(buf));
477 cval = atoi(buf) & 255;
479 i = dlg_listbox_index(cd->listbox, dlg);
481 if (ctrl == cd->redit)
482 cfg->colours[i][0] = cval;
483 else if (ctrl == cd->gedit)
484 cfg->colours[i][1] = cval;
485 else if (ctrl == cd->bedit)
486 cfg->colours[i][2] = cval;
489 } else if (event == EVENT_ACTION) {
490 if (ctrl == cd->button) {
491 int i = dlg_listbox_index(cd->listbox, dlg);
497 * Start a colour selector, which will send us an
498 * EVENT_CALLBACK when it's finished and allow us to
499 * pick up the results.
501 dlg_coloursel_start(ctrl, dlg,
506 } else if (event == EVENT_CALLBACK) {
507 if (ctrl == cd->button) {
508 int i = dlg_listbox_index(cd->listbox, dlg);
510 * Collect the results of the colour selector. Will
511 * return nonzero on success, or zero if the colour
512 * selector did nothing (user hit Cancel, for example).
514 if (dlg_coloursel_results(ctrl, dlg, &r, &g, &b)) {
515 cfg->colours[i][0] = r;
516 cfg->colours[i][1] = g;
517 cfg->colours[i][2] = b;
525 sprintf(buf, "%d", r); dlg_editbox_set(cd->redit, dlg, buf);
526 sprintf(buf, "%d", g); dlg_editbox_set(cd->gedit, dlg, buf);
527 sprintf(buf, "%d", b); dlg_editbox_set(cd->bedit, dlg, buf);
531 struct environ_data {
532 union control *varbox, *valbox, *addbutton, *rembutton, *listbox;
535 static void environ_handler(union control *ctrl, void *dlg,
536 void *data, int event)
538 Config *cfg = (Config *)data;
539 struct environ_data *ed =
540 (struct environ_data *)ctrl->generic.context.p;
542 if (event == EVENT_REFRESH) {
543 if (ctrl == ed->listbox) {
544 char *p = cfg->environmt;
545 dlg_update_start(ctrl, dlg);
546 dlg_listbox_clear(ctrl, dlg);
548 dlg_listbox_add(ctrl, dlg, p);
551 dlg_update_done(ctrl, dlg);
553 } else if (event == EVENT_ACTION) {
554 if (ctrl == ed->addbutton) {
555 char str[sizeof(cfg->environmt)];
557 dlg_editbox_get(ed->varbox, dlg, str, sizeof(str)-1);
562 p = str + strlen(str);
564 dlg_editbox_get(ed->valbox, dlg, p, sizeof(str)-1 - (p - str));
575 if ((p - cfg->environmt) + strlen(str) + 2 <
576 sizeof(cfg->environmt)) {
578 p[strlen(str) + 1] = '\0';
579 dlg_listbox_add(ed->listbox, dlg, str);
580 dlg_editbox_set(ed->varbox, dlg, "");
581 dlg_editbox_set(ed->valbox, dlg, "");
583 dlg_error_msg(dlg, "Environment too big");
585 } else if (ctrl == ed->rembutton) {
586 int i = dlg_listbox_index(ed->listbox, dlg);
592 dlg_listbox_del(ed->listbox, dlg, i);
620 struct portfwd_data {
621 union control *addbutton, *rembutton, *listbox;
622 union control *sourcebox, *destbox, *direction;
625 static void portfwd_handler(union control *ctrl, void *dlg,
626 void *data, int event)
628 Config *cfg = (Config *)data;
629 struct portfwd_data *pfd =
630 (struct portfwd_data *)ctrl->generic.context.p;
632 if (event == EVENT_REFRESH) {
633 if (ctrl == pfd->listbox) {
634 char *p = cfg->portfwd;
635 dlg_update_start(ctrl, dlg);
636 dlg_listbox_clear(ctrl, dlg);
638 dlg_listbox_add(ctrl, dlg, p);
641 dlg_update_done(ctrl, dlg);
642 } else if (ctrl == pfd->direction) {
646 dlg_radiobutton_set(ctrl, dlg, 0);
648 } else if (event == EVENT_ACTION) {
649 if (ctrl == pfd->addbutton) {
650 char str[sizeof(cfg->portfwd)];
652 int whichbutton = dlg_radiobutton_get(pfd->direction, dlg);
653 if (whichbutton == 0)
655 else if (whichbutton == 1)
659 dlg_editbox_get(pfd->sourcebox, dlg, str+1, sizeof(str) - 2);
661 dlg_error_msg(dlg, "You need to specify a source port number");
664 p = str + strlen(str);
667 dlg_editbox_get(pfd->destbox, dlg, p,
668 sizeof(str)-1 - (p - str));
669 if (!*p || !strchr(p, ':')) {
671 "You need to specify a destination address\n"
672 "in the form \"host.name:port\"");
683 if ((p - cfg->portfwd) + strlen(str) + 2 <
684 sizeof(cfg->portfwd)) {
686 p[strlen(str) + 1] = '\0';
687 dlg_listbox_add(pfd->listbox, dlg, str);
688 dlg_editbox_set(pfd->sourcebox, dlg, "");
689 dlg_editbox_set(pfd->destbox, dlg, "");
691 dlg_error_msg(dlg, "Too many forwardings");
693 } else if (ctrl == pfd->rembutton) {
694 int i = dlg_listbox_index(pfd->listbox, dlg);
700 dlg_listbox_del(pfd->listbox, dlg, i);
728 void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
729 int midsession, int protocol)
731 struct controlset *s;
732 struct sessionsaver_data *ssd;
733 struct charclass_data *ccd;
734 struct colour_data *cd;
735 struct environ_data *ed;
736 struct portfwd_data *pfd;
740 ssd = (struct sessionsaver_data *)
741 ctrl_alloc(b, sizeof(struct sessionsaver_data));
742 memset(ssd, 0, sizeof(*ssd));
743 ssd->sesslist = (midsession ? NULL : sesslist);
746 * The standard panel that appears at the bottom of all panels:
747 * Open, Cancel, Apply etc.
749 s = ctrl_getset(b, "", "", "");
750 ctrl_columns(s, 5, 20, 20, 20, 20, 20);
751 ssd->okbutton = ctrl_pushbutton(s,
752 (midsession ? "Apply" : "Open"),
753 (char)(midsession ? 'a' : 'o'),
755 sessionsaver_handler, P(ssd));
756 ssd->okbutton->button.isdefault = TRUE;
757 ssd->okbutton->generic.column = 3;
758 ssd->cancelbutton = ctrl_pushbutton(s, "Cancel", 'c', HELPCTX(no_help),
759 sessionsaver_handler, P(ssd));
760 ssd->cancelbutton->button.iscancel = TRUE;
761 ssd->cancelbutton->generic.column = 4;
762 /* We carefully don't close the 5-column part, so that platform-
763 * specific add-ons can put extra buttons alongside Open and Cancel. */
768 str = dupprintf("Basic options for your %s session", appname);
769 ctrl_settitle(b, "Session", str);
773 s = ctrl_getset(b, "Session", "hostport",
774 "Specify your connection by host name or IP address");
775 ctrl_columns(s, 2, 75, 25);
776 c = ctrl_editbox(s, "Host Name (or IP address)", 'n', 100,
777 HELPCTX(session_hostname),
778 dlg_stdeditbox_handler, I(offsetof(Config,host)),
779 I(sizeof(((Config *)0)->host)));
780 c->generic.column = 0;
781 c = ctrl_editbox(s, "Port", 'p', 100, HELPCTX(session_hostname),
782 dlg_stdeditbox_handler,
783 I(offsetof(Config,port)), I(-1));
784 c->generic.column = 1;
785 ctrl_columns(s, 1, 100);
786 if (backends[3].name == NULL) {
787 ctrl_radiobuttons(s, "Protocol:", NO_SHORTCUT, 3,
788 HELPCTX(session_hostname),
789 protocolbuttons_handler, P(c),
790 "Raw", 'r', I(PROT_RAW),
791 "Telnet", 't', I(PROT_TELNET),
792 "Rlogin", 'i', I(PROT_RLOGIN),
795 ctrl_radiobuttons(s, "Protocol:", NO_SHORTCUT, 4,
796 HELPCTX(session_hostname),
797 protocolbuttons_handler, P(c),
798 "Raw", 'r', I(PROT_RAW),
799 "Telnet", 't', I(PROT_TELNET),
800 "Rlogin", 'i', I(PROT_RLOGIN),
801 "SSH", 's', I(PROT_SSH),
805 s = ctrl_getset(b, "Session", "savedsessions",
806 "Load, save or delete a stored session");
807 ctrl_columns(s, 2, 75, 25);
808 ssd->sesslist = sesslist;
809 ssd->editbox = ctrl_editbox(s, "Saved Sessions", 'e', 100,
810 HELPCTX(session_saved),
811 sessionsaver_handler, P(ssd), P(NULL));
812 ssd->editbox->generic.column = 0;
813 /* Reset columns so that the buttons are alongside the list, rather
814 * than alongside that edit box. */
815 ctrl_columns(s, 1, 100);
816 ctrl_columns(s, 2, 75, 25);
817 ssd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
818 HELPCTX(session_saved),
819 sessionsaver_handler, P(ssd));
820 ssd->listbox->generic.column = 0;
821 ssd->listbox->listbox.height = 7;
822 ssd->loadbutton = ctrl_pushbutton(s, "Load", 'l',
823 HELPCTX(session_saved),
824 sessionsaver_handler, P(ssd));
825 ssd->loadbutton->generic.column = 1;
826 ssd->savebutton = ctrl_pushbutton(s, "Save", 'v',
827 HELPCTX(session_saved),
828 sessionsaver_handler, P(ssd));
829 ssd->savebutton->generic.column = 1;
830 ssd->delbutton = ctrl_pushbutton(s, "Delete", 'd',
831 HELPCTX(session_saved),
832 sessionsaver_handler, P(ssd));
833 ssd->delbutton->generic.column = 1;
834 ctrl_columns(s, 1, 100);
837 s = ctrl_getset(b, "Session", "otheropts", NULL);
838 c = ctrl_radiobuttons(s, "Close window on exit:", 'w', 4,
839 HELPCTX(session_coe),
840 dlg_stdradiobutton_handler,
841 I(offsetof(Config, close_on_exit)),
842 "Always", I(FORCE_ON),
843 "Never", I(FORCE_OFF),
844 "Only on clean exit", I(AUTO), NULL);
847 * The Session/Logging panel.
849 ctrl_settitle(b, "Session/Logging", "Options controlling session logging");
851 s = ctrl_getset(b, "Session/Logging", "main", NULL);
852 ctrl_radiobuttons(s, "Session logging:", NO_SHORTCUT, 1,
853 HELPCTX(logging_main),
854 dlg_stdradiobutton_handler, I(offsetof(Config, logtype)),
855 "Logging turned off completely", 't', I(LGTYP_NONE),
856 "Log printable output only", 'p', I(LGTYP_ASCII),
857 "Log all session output", 'l', I(LGTYP_DEBUG),
858 "Log SSH packet data", 's', I(LGTYP_PACKETS),
860 ctrl_filesel(s, "Log file name:", 'f',
861 NULL, TRUE, "Select session log file name",
862 HELPCTX(logging_filename),
863 dlg_stdfilesel_handler, I(offsetof(Config, logfilename)));
864 ctrl_text(s, "(Log file name can contain &Y, &M, &D for date,"
865 " &T for time, and &H for host name)",
866 HELPCTX(logging_filename));
867 ctrl_radiobuttons(s, "What to do if the log file already exists:", 'e', 1,
868 HELPCTX(logging_exists),
869 dlg_stdradiobutton_handler, I(offsetof(Config,logxfovr)),
870 "Always overwrite it", I(LGXF_OVR),
871 "Always append to the end of it", I(LGXF_APN),
872 "Ask the user every time", I(LGXF_ASK), NULL);
875 * The Terminal panel.
877 ctrl_settitle(b, "Terminal", "Options controlling the terminal emulation");
879 s = ctrl_getset(b, "Terminal", "general", "Set various terminal options");
880 ctrl_checkbox(s, "Auto wrap mode initially on", 'w',
881 HELPCTX(terminal_autowrap),
882 dlg_stdcheckbox_handler, I(offsetof(Config,wrap_mode)));
883 ctrl_checkbox(s, "DEC Origin Mode initially on", 'd',
884 HELPCTX(terminal_decom),
885 dlg_stdcheckbox_handler, I(offsetof(Config,dec_om)));
886 ctrl_checkbox(s, "Implicit CR in every LF", 'r',
887 HELPCTX(terminal_lfhascr),
888 dlg_stdcheckbox_handler, I(offsetof(Config,lfhascr)));
889 ctrl_checkbox(s, "Use background colour to erase screen", 'e',
890 HELPCTX(terminal_bce),
891 dlg_stdcheckbox_handler, I(offsetof(Config,bce)));
892 ctrl_checkbox(s, "Enable blinking text", 'n',
893 HELPCTX(terminal_blink),
894 dlg_stdcheckbox_handler, I(offsetof(Config,blinktext)));
895 ctrl_editbox(s, "Answerback to ^E:", 's', 100,
896 HELPCTX(terminal_answerback),
897 dlg_stdeditbox_handler, I(offsetof(Config,answerback)),
898 I(sizeof(((Config *)0)->answerback)));
900 s = ctrl_getset(b, "Terminal", "ldisc", "Line discipline options");
901 ctrl_radiobuttons(s, "Local echo:", 'l', 3,
902 HELPCTX(terminal_localecho),
903 dlg_stdradiobutton_handler,I(offsetof(Config,localecho)),
905 "Force on", I(FORCE_ON),
906 "Force off", I(FORCE_OFF), NULL);
907 ctrl_radiobuttons(s, "Local line editing:", 't', 3,
908 HELPCTX(terminal_localedit),
909 dlg_stdradiobutton_handler,I(offsetof(Config,localedit)),
911 "Force on", I(FORCE_ON),
912 "Force off", I(FORCE_OFF), NULL);
914 s = ctrl_getset(b, "Terminal", "printing", "Remote-controlled printing");
915 ctrl_combobox(s, "Printer to send ANSI printer output to:", 'p', 100,
916 HELPCTX(terminal_printing),
917 printerbox_handler, P(NULL), P(NULL));
920 * The Terminal/Keyboard panel.
922 ctrl_settitle(b, "Terminal/Keyboard",
923 "Options controlling the effects of keys");
925 s = ctrl_getset(b, "Terminal/Keyboard", "mappings",
926 "Change the sequences sent by:");
927 ctrl_radiobuttons(s, "The Backspace key", 'b', 2,
928 HELPCTX(keyboard_backspace),
929 dlg_stdradiobutton_handler,
930 I(offsetof(Config, bksp_is_delete)),
931 "Control-H", I(0), "Control-? (127)", I(1), NULL);
932 ctrl_radiobuttons(s, "The Home and End keys", 'e', 2,
933 HELPCTX(keyboard_homeend),
934 dlg_stdradiobutton_handler,
935 I(offsetof(Config, rxvt_homeend)),
936 "Standard", I(0), "rxvt", I(1), NULL);
937 ctrl_radiobuttons(s, "The Function keys and keypad", 'f', 3,
938 HELPCTX(keyboard_funkeys),
939 dlg_stdradiobutton_handler,
940 I(offsetof(Config, funky_type)),
941 "ESC[n~", I(0), "Linux", I(1), "Xterm R6", I(2),
942 "VT400", I(3), "VT100+", I(4), "SCO", I(5), NULL);
944 s = ctrl_getset(b, "Terminal/Keyboard", "appkeypad",
945 "Application keypad settings:");
946 ctrl_radiobuttons(s, "Initial state of cursor keys:", 'r', 3,
947 HELPCTX(keyboard_appcursor),
948 dlg_stdradiobutton_handler,
949 I(offsetof(Config, app_cursor)),
950 "Normal", I(0), "Application", I(1), NULL);
951 ctrl_radiobuttons(s, "Initial state of numeric keypad:", 'n', 3,
952 HELPCTX(keyboard_appkeypad),
953 numeric_keypad_handler, P(NULL),
954 "Normal", I(0), "Application", I(1), "NetHack", I(2),
958 * The Terminal/Bell panel.
960 ctrl_settitle(b, "Terminal/Bell",
961 "Options controlling the terminal bell");
963 s = ctrl_getset(b, "Terminal/Bell", "style", "Set the style of bell");
964 ctrl_radiobuttons(s, "Action to happen when a bell occurs:", 'b', 1,
966 dlg_stdradiobutton_handler, I(offsetof(Config, beep)),
967 "None (bell disabled)", I(BELL_DISABLED),
968 "Make default system alert sound", I(BELL_DEFAULT),
969 "Visual bell (flash window)", I(BELL_VISUAL), NULL);
971 s = ctrl_getset(b, "Terminal/Bell", "overload",
972 "Control the bell overload behaviour");
973 ctrl_checkbox(s, "Bell is temporarily disabled when over-used", 'd',
974 HELPCTX(bell_overload),
975 dlg_stdcheckbox_handler, I(offsetof(Config,bellovl)));
976 ctrl_editbox(s, "Over-use means this many bells...", 'm', 20,
977 HELPCTX(bell_overload),
978 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_n)), I(-1));
979 ctrl_editbox(s, "... in this many seconds", 't', 20,
980 HELPCTX(bell_overload),
981 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_t)),
983 ctrl_text(s, "The bell is re-enabled after a few seconds of silence.",
984 HELPCTX(bell_overload));
985 ctrl_editbox(s, "Seconds of silence required", 's', 20,
986 HELPCTX(bell_overload),
987 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_s)),
991 * The Terminal/Features panel.
993 ctrl_settitle(b, "Terminal/Features",
994 "Enabling and disabling advanced terminal features");
996 s = ctrl_getset(b, "Terminal/Features", "main", NULL);
997 ctrl_checkbox(s, "Disable application cursor keys mode", 'u',
998 HELPCTX(features_application),
999 dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_c)));
1000 ctrl_checkbox(s, "Disable application keypad mode", 'k',
1001 HELPCTX(features_application),
1002 dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_k)));
1003 ctrl_checkbox(s, "Disable xterm-style mouse reporting", 'x',
1004 HELPCTX(features_mouse),
1005 dlg_stdcheckbox_handler, I(offsetof(Config,no_mouse_rep)));
1006 ctrl_checkbox(s, "Disable remote-controlled terminal resizing", 's',
1007 HELPCTX(features_resize),
1008 dlg_stdcheckbox_handler,
1009 I(offsetof(Config,no_remote_resize)));
1010 ctrl_checkbox(s, "Disable switching to alternate terminal screen", 'w',
1011 HELPCTX(features_altscreen),
1012 dlg_stdcheckbox_handler, I(offsetof(Config,no_alt_screen)));
1013 ctrl_checkbox(s, "Disable remote-controlled window title changing", 't',
1014 HELPCTX(features_retitle),
1015 dlg_stdcheckbox_handler,
1016 I(offsetof(Config,no_remote_wintitle)));
1017 ctrl_checkbox(s, "Disable destructive backspace on server sending ^?",'b',
1018 HELPCTX(features_dbackspace),
1019 dlg_stdcheckbox_handler, I(offsetof(Config,no_dbackspace)));
1020 ctrl_checkbox(s, "Disable remote-controlled character set configuration",
1021 'r', HELPCTX(features_charset), dlg_stdcheckbox_handler,
1022 I(offsetof(Config,no_remote_charset)));
1027 str = dupprintf("Options controlling %s's window", appname);
1028 ctrl_settitle(b, "Window", str);
1031 s = ctrl_getset(b, "Window", "size", "Set the size of the window");
1032 ctrl_columns(s, 2, 50, 50);
1033 c = ctrl_editbox(s, "Rows", 'r', 100,
1034 HELPCTX(window_size),
1035 dlg_stdeditbox_handler, I(offsetof(Config,height)),I(-1));
1036 c->generic.column = 0;
1037 c = ctrl_editbox(s, "Columns", 'm', 100,
1038 HELPCTX(window_size),
1039 dlg_stdeditbox_handler, I(offsetof(Config,width)), I(-1));
1040 c->generic.column = 1;
1041 ctrl_columns(s, 1, 100);
1043 s = ctrl_getset(b, "Window", "scrollback",
1044 "Control the scrollback in the window");
1045 ctrl_editbox(s, "Lines of scrollback", 's', 50,
1046 HELPCTX(window_scrollback),
1047 dlg_stdeditbox_handler, I(offsetof(Config,savelines)), I(-1));
1048 ctrl_checkbox(s, "Display scrollbar", 'd',
1049 HELPCTX(window_scrollback),
1050 dlg_stdcheckbox_handler, I(offsetof(Config,scrollbar)));
1051 ctrl_checkbox(s, "Reset scrollback on keypress", 'k',
1052 HELPCTX(window_scrollback),
1053 dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_key)));
1054 ctrl_checkbox(s, "Reset scrollback on display activity", 'p',
1055 HELPCTX(window_scrollback),
1056 dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_disp)));
1057 ctrl_checkbox(s, "Push erased text into scrollback", 'e',
1058 HELPCTX(window_erased),
1059 dlg_stdcheckbox_handler,
1060 I(offsetof(Config,erase_to_scrollback)));
1063 * The Window/Appearance panel.
1065 str = dupprintf("Configure the appearance of %s's window", appname);
1066 ctrl_settitle(b, "Window/Appearance", str);
1069 s = ctrl_getset(b, "Window/Appearance", "cursor",
1070 "Adjust the use of the cursor");
1071 ctrl_radiobuttons(s, "Cursor appearance:", NO_SHORTCUT, 3,
1072 HELPCTX(appearance_cursor),
1073 dlg_stdradiobutton_handler,
1074 I(offsetof(Config, cursor_type)),
1076 "Underline", 'u', I(1),
1077 "Vertical line", 'v', I(2), NULL);
1078 ctrl_checkbox(s, "Cursor blinks", 'b',
1079 HELPCTX(appearance_cursor),
1080 dlg_stdcheckbox_handler, I(offsetof(Config,blink_cur)));
1082 s = ctrl_getset(b, "Window/Appearance", "font",
1084 ctrl_fontsel(s, "Font used in the terminal window", 'n',
1085 HELPCTX(appearance_font),
1086 dlg_stdfontsel_handler, I(offsetof(Config, font)));
1088 s = ctrl_getset(b, "Window/Appearance", "mouse",
1089 "Adjust the use of the mouse pointer");
1090 ctrl_checkbox(s, "Hide mouse pointer when typing in window", 'p',
1091 HELPCTX(appearance_hidemouse),
1092 dlg_stdcheckbox_handler, I(offsetof(Config,hide_mouseptr)));
1094 s = ctrl_getset(b, "Window/Appearance", "border",
1095 "Adjust the window border");
1096 ctrl_editbox(s, "Gap between text and window edge:", NO_SHORTCUT, 20,
1097 HELPCTX(appearance_border),
1098 dlg_stdeditbox_handler,
1099 I(offsetof(Config,window_border)), I(-1));
1102 * The Window/Behaviour panel.
1104 str = dupprintf("Configure the behaviour of %s's window", appname);
1105 ctrl_settitle(b, "Window/Behaviour", str);
1108 s = ctrl_getset(b, "Window/Behaviour", "title",
1109 "Adjust the behaviour of the window title");
1110 ctrl_editbox(s, "Window title:", 't', 100,
1111 HELPCTX(appearance_title),
1112 dlg_stdeditbox_handler, I(offsetof(Config,wintitle)),
1113 I(sizeof(((Config *)0)->wintitle)));
1114 ctrl_checkbox(s, "Separate window and icon titles", 'i',
1115 HELPCTX(appearance_title),
1116 dlg_stdcheckbox_handler,
1117 I(CHECKBOX_INVERT | offsetof(Config,win_name_always)));
1119 s = ctrl_getset(b, "Window/Behaviour", "main", NULL);
1120 ctrl_checkbox(s, "Warn before closing window", 'w',
1121 HELPCTX(behaviour_closewarn),
1122 dlg_stdcheckbox_handler, I(offsetof(Config,warn_on_close)));
1125 * The Window/Translation panel.
1127 ctrl_settitle(b, "Window/Translation",
1128 "Options controlling character set translation");
1130 s = ctrl_getset(b, "Window/Translation", "trans",
1131 "Character set translation on received data");
1132 ctrl_combobox(s, "Received data assumed to be in which character set:",
1133 'r', 100, HELPCTX(translation_codepage),
1134 codepage_handler, P(NULL), P(NULL));
1136 str = dupprintf("Adjust how %s displays line drawing characters", appname);
1137 s = ctrl_getset(b, "Window/Translation", "linedraw", str);
1139 ctrl_radiobuttons(s, "Handling of line drawing characters:", NO_SHORTCUT,1,
1140 HELPCTX(translation_linedraw),
1141 dlg_stdradiobutton_handler,
1142 I(offsetof(Config, vtmode)),
1143 "Font has XWindows encoding", 'x', I(VT_XWINDOWS),
1144 "Poor man's line drawing (+, - and |)",'p',I(VT_POORMAN),
1145 "Unicode mode", 'u', I(VT_UNICODE), NULL);
1148 * The Window/Selection panel.
1150 ctrl_settitle(b, "Window/Selection", "Options controlling copy and paste");
1152 s = ctrl_getset(b, "Window/Selection", "trans",
1153 "Translation of pasted characters");
1154 ctrl_checkbox(s, "Don't translate line drawing chars into +, - and |",'d',
1155 HELPCTX(selection_linedraw),
1156 dlg_stdcheckbox_handler, I(offsetof(Config,rawcnp)));
1158 s = ctrl_getset(b, "Window/Selection", "mouse",
1159 "Control use of mouse");
1160 ctrl_checkbox(s, "Shift overrides application's use of mouse", 'p',
1161 HELPCTX(selection_shiftdrag),
1162 dlg_stdcheckbox_handler, I(offsetof(Config,mouse_override)));
1163 ctrl_radiobuttons(s,
1164 "Default selection mode (Alt+drag does the other one):",
1166 HELPCTX(selection_rect),
1167 dlg_stdradiobutton_handler,
1168 I(offsetof(Config, rect_select)),
1169 "Normal", 'n', I(0),
1170 "Rectangular block", 'r', I(1), NULL);
1172 s = ctrl_getset(b, "Window/Selection", "charclass",
1173 "Control the select-one-word-at-a-time mode");
1174 ccd = (struct charclass_data *)
1175 ctrl_alloc(b, sizeof(struct charclass_data));
1176 ccd->listbox = ctrl_listbox(s, "Character classes:", 'e',
1177 HELPCTX(selection_charclasses),
1178 charclass_handler, P(ccd));
1179 ccd->listbox->listbox.multisel = 1;
1180 ccd->listbox->listbox.ncols = 4;
1181 ccd->listbox->listbox.percentages = snewn(4, int);
1182 ccd->listbox->listbox.percentages[0] = 15;
1183 ccd->listbox->listbox.percentages[1] = 25;
1184 ccd->listbox->listbox.percentages[2] = 20;
1185 ccd->listbox->listbox.percentages[3] = 40;
1186 ctrl_columns(s, 2, 67, 33);
1187 ccd->editbox = ctrl_editbox(s, "Set to class", 't', 50,
1188 HELPCTX(selection_charclasses),
1189 charclass_handler, P(ccd), P(NULL));
1190 ccd->editbox->generic.column = 0;
1191 ccd->button = ctrl_pushbutton(s, "Set", 's',
1192 HELPCTX(selection_charclasses),
1193 charclass_handler, P(ccd));
1194 ccd->button->generic.column = 1;
1195 ctrl_columns(s, 1, 100);
1198 * The Window/Colours panel.
1200 ctrl_settitle(b, "Window/Colours", "Options controlling use of colours");
1202 s = ctrl_getset(b, "Window/Colours", "general",
1203 "General options for colour usage");
1204 ctrl_checkbox(s, "Bolded text is a different colour", 'b',
1205 HELPCTX(colours_bold),
1206 dlg_stdcheckbox_handler, I(offsetof(Config,bold_colour)));
1208 str = dupprintf("Adjust the precise colours %s displays", appname);
1209 s = ctrl_getset(b, "Window/Colours", "adjust", str);
1211 ctrl_text(s, "Select a colour from the list, and then click the"
1212 " Modify button to change its appearance.",
1213 HELPCTX(colours_config));
1214 ctrl_columns(s, 2, 67, 33);
1215 cd = (struct colour_data *)ctrl_alloc(b, sizeof(struct colour_data));
1216 cd->listbox = ctrl_listbox(s, "Select a colour to adjust:", 'u',
1217 HELPCTX(colours_config), colour_handler, P(cd));
1218 cd->listbox->generic.column = 0;
1219 cd->listbox->listbox.height = 7;
1220 c = ctrl_text(s, "RGB value:", HELPCTX(colours_config));
1221 c->generic.column = 1;
1222 cd->redit = ctrl_editbox(s, "Red", 'r', 50, HELPCTX(colours_config),
1223 colour_handler, P(cd), P(NULL));
1224 cd->redit->generic.column = 1;
1225 cd->gedit = ctrl_editbox(s, "Green", 'n', 50, HELPCTX(colours_config),
1226 colour_handler, P(cd), P(NULL));
1227 cd->gedit->generic.column = 1;
1228 cd->bedit = ctrl_editbox(s, "Blue", 'e', 50, HELPCTX(colours_config),
1229 colour_handler, P(cd), P(NULL));
1230 cd->bedit->generic.column = 1;
1231 cd->button = ctrl_pushbutton(s, "Modify", 'm', HELPCTX(colours_config),
1232 colour_handler, P(cd));
1233 cd->button->generic.column = 1;
1234 ctrl_columns(s, 1, 100);
1237 * The Connection panel.
1239 ctrl_settitle(b, "Connection", "Options controlling the connection");
1242 s = ctrl_getset(b, "Connection", "data", "Data to send to the server");
1243 ctrl_editbox(s, "Terminal-type string", 't', 50,
1244 HELPCTX(connection_termtype),
1245 dlg_stdeditbox_handler, I(offsetof(Config,termtype)),
1246 I(sizeof(((Config *)0)->termtype)));
1247 ctrl_editbox(s, "Auto-login username", 'u', 50,
1248 HELPCTX(connection_username),
1249 dlg_stdeditbox_handler, I(offsetof(Config,username)),
1250 I(sizeof(((Config *)0)->username)));
1253 s = ctrl_getset(b, "Connection", "keepalive",
1254 "Sending of null packets to keep session active");
1255 ctrl_editbox(s, "Seconds between keepalives (0 to turn off)", 'k', 20,
1256 HELPCTX(connection_keepalive),
1257 dlg_stdeditbox_handler, I(offsetof(Config,ping_interval)),
1261 s = ctrl_getset(b, "Connection", "tcp",
1262 "Low-level TCP connection options");
1263 ctrl_checkbox(s, "Disable Nagle's algorithm (TCP_NODELAY option)", 'n',
1264 HELPCTX(connection_nodelay),
1265 dlg_stdcheckbox_handler,
1266 I(offsetof(Config,tcp_nodelay)));
1271 * The Connection/Proxy panel.
1273 ctrl_settitle(b, "Connection/Proxy",
1274 "Options controlling proxy usage");
1276 s = ctrl_getset(b, "Connection/Proxy", "basics", "Proxy basics");
1277 ctrl_radiobuttons(s, "Proxy type:", NO_SHORTCUT, 4,
1278 HELPCTX(proxy_type),
1279 dlg_stdradiobutton_handler,
1280 I(offsetof(Config, proxy_type)),
1281 "None", 'n', I(PROXY_NONE),
1282 "HTTP", 't', I(PROXY_HTTP),
1283 "SOCKS", 's', I(PROXY_SOCKS),
1284 "Telnet", 'l', I(PROXY_TELNET),
1286 ctrl_columns(s, 2, 80, 20);
1287 c = ctrl_editbox(s, "Proxy hostname", 'y', 100,
1288 HELPCTX(proxy_main),
1289 dlg_stdeditbox_handler,
1290 I(offsetof(Config,proxy_host)),
1291 I(sizeof(((Config *)0)->proxy_host)));
1292 c->generic.column = 0;
1293 c = ctrl_editbox(s, "Port", 'p', 100,
1294 HELPCTX(proxy_main),
1295 dlg_stdeditbox_handler,
1296 I(offsetof(Config,proxy_port)),
1298 c->generic.column = 1;
1299 ctrl_columns(s, 1, 100);
1300 ctrl_editbox(s, "Exclude Hosts/IPs", 'e', 100,
1301 HELPCTX(proxy_exclude),
1302 dlg_stdeditbox_handler,
1303 I(offsetof(Config,proxy_exclude_list)),
1304 I(sizeof(((Config *)0)->proxy_exclude_list)));
1305 ctrl_checkbox(s, "Consider proxying local host connections", 'x',
1306 HELPCTX(proxy_exclude),
1307 dlg_stdcheckbox_handler,
1308 I(offsetof(Config,even_proxy_localhost)));
1309 ctrl_radiobuttons(s, "Do DNS name lookup at proxy end:", 'd', 3,
1311 dlg_stdradiobutton_handler,
1312 I(offsetof(Config, proxy_dns)),
1315 "Yes", I(FORCE_ON), NULL);
1316 ctrl_editbox(s, "Username", 'u', 60,
1317 HELPCTX(proxy_auth),
1318 dlg_stdeditbox_handler,
1319 I(offsetof(Config,proxy_username)),
1320 I(sizeof(((Config *)0)->proxy_username)));
1321 c = ctrl_editbox(s, "Password", 'w', 60,
1322 HELPCTX(proxy_auth),
1323 dlg_stdeditbox_handler,
1324 I(offsetof(Config,proxy_password)),
1325 I(sizeof(((Config *)0)->proxy_password)));
1326 c->editbox.password = 1;
1328 s = ctrl_getset(b, "Connection/Proxy", "misc",
1329 "Miscellaneous proxy settings");
1330 ctrl_editbox(s, "Telnet command", 'm', 100,
1331 HELPCTX(proxy_command),
1332 dlg_stdeditbox_handler,
1333 I(offsetof(Config,proxy_telnet_command)),
1334 I(sizeof(((Config *)0)->proxy_telnet_command)));
1335 ctrl_radiobuttons(s, "SOCKS Version", 'v', 2,
1336 HELPCTX(proxy_socksver),
1337 dlg_stdradiobutton_handler,
1338 I(offsetof(Config, proxy_socks_version)),
1339 "Version 5", I(5), "Version 4", I(4), NULL);
1343 * The Telnet panel exists in the base config box, and in a
1344 * mid-session reconfig box _if_ we're using Telnet.
1346 if (!midsession || protocol == PROT_TELNET) {
1348 * The Connection/Telnet panel.
1350 ctrl_settitle(b, "Connection/Telnet",
1351 "Options controlling Telnet connections");
1354 s = ctrl_getset(b, "Connection/Telnet", "data",
1355 "Data to send to the server");
1356 ctrl_editbox(s, "Terminal-speed string", 's', 50,
1357 HELPCTX(telnet_termspeed),
1358 dlg_stdeditbox_handler, I(offsetof(Config,termspeed)),
1359 I(sizeof(((Config *)0)->termspeed)));
1360 ctrl_text(s, "Environment variables:", HELPCTX(telnet_environ));
1361 ctrl_columns(s, 2, 80, 20);
1362 ed = (struct environ_data *)
1363 ctrl_alloc(b, sizeof(struct environ_data));
1364 ed->varbox = ctrl_editbox(s, "Variable", 'v', 60,
1365 HELPCTX(telnet_environ),
1366 environ_handler, P(ed), P(NULL));
1367 ed->varbox->generic.column = 0;
1368 ed->valbox = ctrl_editbox(s, "Value", 'l', 60,
1369 HELPCTX(telnet_environ),
1370 environ_handler, P(ed), P(NULL));
1371 ed->valbox->generic.column = 0;
1372 ed->addbutton = ctrl_pushbutton(s, "Add", 'd',
1373 HELPCTX(telnet_environ),
1374 environ_handler, P(ed));
1375 ed->addbutton->generic.column = 1;
1376 ed->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1377 HELPCTX(telnet_environ),
1378 environ_handler, P(ed));
1379 ed->rembutton->generic.column = 1;
1380 ctrl_columns(s, 1, 100);
1381 ed->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1382 HELPCTX(telnet_environ),
1383 environ_handler, P(ed));
1384 ed->listbox->listbox.height = 3;
1385 ed->listbox->listbox.ncols = 2;
1386 ed->listbox->listbox.percentages = snewn(2, int);
1387 ed->listbox->listbox.percentages[0] = 30;
1388 ed->listbox->listbox.percentages[1] = 70;
1391 s = ctrl_getset(b, "Connection/Telnet", "protocol",
1392 "Telnet protocol adjustments");
1395 ctrl_radiobuttons(s, "Handling of OLD_ENVIRON ambiguity:",
1397 HELPCTX(telnet_oldenviron),
1398 dlg_stdradiobutton_handler,
1399 I(offsetof(Config, rfc_environ)),
1400 "BSD (commonplace)", 'b', I(0),
1401 "RFC 1408 (unusual)", 'f', I(1), NULL);
1402 ctrl_radiobuttons(s, "Telnet negotiation mode:", 't', 2,
1403 HELPCTX(telnet_passive),
1404 dlg_stdradiobutton_handler,
1405 I(offsetof(Config, passive_telnet)),
1406 "Passive", I(1), "Active", I(0), NULL);
1408 ctrl_checkbox(s, "Keyboard sends telnet Backspace and Interrupt", 'k',
1409 HELPCTX(telnet_specialkeys),
1410 dlg_stdcheckbox_handler,
1411 I(offsetof(Config,telnet_keyboard)));
1412 ctrl_checkbox(s, "Return key sends telnet New Line instead of ^M",
1413 NO_SHORTCUT, HELPCTX(telnet_newline),
1414 dlg_stdcheckbox_handler,
1415 I(offsetof(Config,telnet_newline)));
1421 * The Connection/Rlogin panel.
1423 ctrl_settitle(b, "Connection/Rlogin",
1424 "Options controlling Rlogin connections");
1426 s = ctrl_getset(b, "Connection/Rlogin", "data",
1427 "Data to send to the server");
1428 ctrl_editbox(s, "Terminal-speed string", 's', 50,
1429 HELPCTX(rlogin_termspeed),
1430 dlg_stdeditbox_handler, I(offsetof(Config,termspeed)),
1431 I(sizeof(((Config *)0)->termspeed)));
1432 ctrl_editbox(s, "Local username:", 'l', 50,
1433 HELPCTX(rlogin_localuser),
1434 dlg_stdeditbox_handler, I(offsetof(Config,localusername)),
1435 I(sizeof(((Config *)0)->localusername)));
1440 * All the SSH stuff is omitted in PuTTYtel.
1443 if (!midsession && backends[3].name != NULL) {
1446 * The Connection/SSH panel.
1448 ctrl_settitle(b, "Connection/SSH",
1449 "Options controlling SSH connections");
1451 s = ctrl_getset(b, "Connection/SSH", "data",
1452 "Data to send to the server");
1453 ctrl_editbox(s, "Remote command:", 'r', 100,
1454 HELPCTX(ssh_command),
1455 dlg_stdeditbox_handler, I(offsetof(Config,remote_cmd)),
1456 I(sizeof(((Config *)0)->remote_cmd)));
1458 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1459 ctrl_checkbox(s, "Don't allocate a pseudo-terminal", 'p',
1461 dlg_stdcheckbox_handler,
1462 I(offsetof(Config,nopty)));
1463 ctrl_checkbox(s, "Enable compression", 'e',
1464 HELPCTX(ssh_compress),
1465 dlg_stdcheckbox_handler,
1466 I(offsetof(Config,compression)));
1467 ctrl_radiobuttons(s, "Preferred SSH protocol version:", NO_SHORTCUT, 4,
1468 HELPCTX(ssh_protocol),
1469 dlg_stdradiobutton_handler,
1470 I(offsetof(Config, sshprot)),
1471 "1 only", 'l', I(0),
1474 "2 only", 'n', I(3), NULL);
1476 s = ctrl_getset(b, "Connection/SSH", "encryption", "Encryption options");
1477 c = ctrl_draglist(s, "Encryption cipher selection policy:", 's',
1478 HELPCTX(ssh_ciphers),
1479 cipherlist_handler, P(NULL));
1480 c->listbox.height = 6;
1482 ctrl_checkbox(s, "Enable non-standard use of single-DES in SSH 2", 'i',
1483 HELPCTX(ssh_ciphers),
1484 dlg_stdcheckbox_handler,
1485 I(offsetof(Config,ssh2_des_cbc)));
1488 * The Connection/SSH/Auth panel.
1490 ctrl_settitle(b, "Connection/SSH/Auth",
1491 "Options controlling SSH authentication");
1493 s = ctrl_getset(b, "Connection/SSH/Auth", "methods",
1494 "Authentication methods");
1495 ctrl_checkbox(s, "Attempt TIS or CryptoCard auth (SSH1)", 'm',
1496 HELPCTX(ssh_auth_tis),
1497 dlg_stdcheckbox_handler,
1498 I(offsetof(Config,try_tis_auth)));
1499 ctrl_checkbox(s, "Attempt \"keyboard-interactive\" auth (SSH2)",
1500 'i', HELPCTX(ssh_auth_ki),
1501 dlg_stdcheckbox_handler,
1502 I(offsetof(Config,try_ki_auth)));
1504 s = ctrl_getset(b, "Connection/SSH/Auth", "params",
1505 "Authentication parameters");
1506 ctrl_checkbox(s, "Allow agent forwarding", 'f',
1507 HELPCTX(ssh_auth_agentfwd),
1508 dlg_stdcheckbox_handler, I(offsetof(Config,agentfwd)));
1509 ctrl_checkbox(s, "Allow attempted changes of username in SSH2", 'u',
1510 HELPCTX(ssh_auth_changeuser),
1511 dlg_stdcheckbox_handler,
1512 I(offsetof(Config,change_username)));
1513 ctrl_filesel(s, "Private key file for authentication:", 'k',
1514 FILTER_KEY_FILES, FALSE, "Select private key file",
1515 HELPCTX(ssh_auth_privkey),
1516 dlg_stdfilesel_handler, I(offsetof(Config, keyfile)));
1519 * The Connection/SSH/Tunnels panel.
1521 ctrl_settitle(b, "Connection/SSH/Tunnels",
1522 "Options controlling SSH tunnelling");
1524 s = ctrl_getset(b, "Connection/SSH/Tunnels", "x11", "X11 forwarding");
1525 ctrl_checkbox(s, "Enable X11 forwarding", 'e',
1526 HELPCTX(ssh_tunnels_x11),
1527 dlg_stdcheckbox_handler,I(offsetof(Config,x11_forward)));
1528 ctrl_editbox(s, "X display location", 'x', 50,
1529 HELPCTX(ssh_tunnels_x11),
1530 dlg_stdeditbox_handler, I(offsetof(Config,x11_display)),
1531 I(sizeof(((Config *)0)->x11_display)));
1532 ctrl_radiobuttons(s, "Remote X11 authentication protocol", 'u', 2,
1533 HELPCTX(ssh_tunnels_x11auth),
1534 dlg_stdradiobutton_handler,
1535 I(offsetof(Config, x11_auth)),
1536 "MIT-Magic-Cookie-1", I(X11_MIT),
1537 "XDM-Authorization-1", I(X11_XDM), NULL);
1539 s = ctrl_getset(b, "Connection/SSH/Tunnels", "portfwd",
1541 ctrl_checkbox(s, "Local ports accept connections from other hosts",'t',
1542 HELPCTX(ssh_tunnels_portfwd_localhost),
1543 dlg_stdcheckbox_handler,
1544 I(offsetof(Config,lport_acceptall)));
1545 ctrl_checkbox(s, "Remote ports do the same (SSH v2 only)", 'p',
1546 HELPCTX(ssh_tunnels_portfwd_localhost),
1547 dlg_stdcheckbox_handler,
1548 I(offsetof(Config,rport_acceptall)));
1550 ctrl_columns(s, 3, 55, 20, 25);
1551 c = ctrl_text(s, "Forwarded ports:", HELPCTX(ssh_tunnels_portfwd));
1552 c->generic.column = COLUMN_FIELD(0,2);
1553 /* You want to select from the list, _then_ hit Remove. So tab order
1554 * should be that way round. */
1555 pfd = (struct portfwd_data *)ctrl_alloc(b,sizeof(struct portfwd_data));
1556 pfd->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1557 HELPCTX(ssh_tunnels_portfwd),
1558 portfwd_handler, P(pfd));
1559 pfd->rembutton->generic.column = 2;
1560 pfd->rembutton->generic.tabdelay = 1;
1561 pfd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1562 HELPCTX(ssh_tunnels_portfwd),
1563 portfwd_handler, P(pfd));
1564 pfd->listbox->listbox.height = 3;
1565 pfd->listbox->listbox.ncols = 2;
1566 pfd->listbox->listbox.percentages = snewn(2, int);
1567 pfd->listbox->listbox.percentages[0] = 20;
1568 pfd->listbox->listbox.percentages[1] = 80;
1569 ctrl_tabdelay(s, pfd->rembutton);
1570 ctrl_text(s, "Add new forwarded port:", HELPCTX(ssh_tunnels_portfwd));
1571 /* You want to enter source, destination and type, _then_ hit Add.
1572 * Again, we adjust the tab order to reflect this. */
1573 pfd->addbutton = ctrl_pushbutton(s, "Add", 'd',
1574 HELPCTX(ssh_tunnels_portfwd),
1575 portfwd_handler, P(pfd));
1576 pfd->addbutton->generic.column = 2;
1577 pfd->addbutton->generic.tabdelay = 1;
1578 pfd->sourcebox = ctrl_editbox(s, "Source port", 's', 40,
1579 HELPCTX(ssh_tunnels_portfwd),
1580 portfwd_handler, P(pfd), P(NULL));
1581 pfd->sourcebox->generic.column = 0;
1582 pfd->destbox = ctrl_editbox(s, "Destination", 'i', 67,
1583 HELPCTX(ssh_tunnels_portfwd),
1584 portfwd_handler, P(pfd), P(NULL));
1585 pfd->direction = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
1586 HELPCTX(ssh_tunnels_portfwd),
1587 portfwd_handler, P(pfd),
1588 "Local", 'l', P(NULL),
1589 "Remote", 'm', P(NULL),
1590 "Dynamic", 'y', P(NULL),
1592 ctrl_tabdelay(s, pfd->addbutton);
1593 ctrl_columns(s, 1, 100);
1596 * The Connection/SSH/Bugs panel.
1598 ctrl_settitle(b, "Connection/SSH/Bugs",
1599 "Workarounds for SSH server bugs");
1601 s = ctrl_getset(b, "Connection/SSH/Bugs", "main",
1602 "Detection of known bugs in SSH servers");
1603 ctrl_droplist(s, "Chokes on SSH1 ignore messages", 'i', 20,
1604 HELPCTX(ssh_bugs_ignore1),
1605 sshbug_handler, I(offsetof(Config,sshbug_ignore1)));
1606 ctrl_droplist(s, "Refuses all SSH1 password camouflage", 's', 20,
1607 HELPCTX(ssh_bugs_plainpw1),
1608 sshbug_handler, I(offsetof(Config,sshbug_plainpw1)));
1609 ctrl_droplist(s, "Chokes on SSH1 RSA authentication", 'r', 20,
1610 HELPCTX(ssh_bugs_rsa1),
1611 sshbug_handler, I(offsetof(Config,sshbug_rsa1)));
1612 ctrl_droplist(s, "Miscomputes SSH2 HMAC keys", 'm', 20,
1613 HELPCTX(ssh_bugs_hmac2),
1614 sshbug_handler, I(offsetof(Config,sshbug_hmac2)));
1615 ctrl_droplist(s, "Miscomputes SSH2 encryption keys", 'e', 20,
1616 HELPCTX(ssh_bugs_derivekey2),
1617 sshbug_handler, I(offsetof(Config,sshbug_derivekey2)));
1618 ctrl_droplist(s, "Requires padding on SSH2 RSA signatures", 'p', 20,
1619 HELPCTX(ssh_bugs_rsapad2),
1620 sshbug_handler, I(offsetof(Config,sshbug_rsapad2)));
1621 ctrl_droplist(s, "Chokes on Diffie-Hellman group exchange", 'd', 20,
1622 HELPCTX(ssh_bugs_dhgex2),
1623 sshbug_handler, I(offsetof(Config,sshbug_dhgex2)));
1624 ctrl_droplist(s, "Misuses the session ID in PK auth", 'n', 20,
1625 HELPCTX(ssh_bugs_pksessid2),
1626 sshbug_handler, I(offsetof(Config,sshbug_pksessid2)));