Mention that sessions can be saved from "Change Settings" in using.but.
[u/mdw/putty] / config.c
CommitLineData
fe8abbf4 1/*
2 * config.c - the platform-independent parts of the PuTTY
3 * configuration box.
4 */
5
6#include <assert.h>
7#include <stdlib.h>
8
9#include "putty.h"
10#include "dialog.h"
11#include "storage.h"
12
13#define PRINTER_DISABLED_STRING "None (printing disabled)"
14
15static void protocolbuttons_handler(union control *ctrl, void *dlg,
16 void *data, int event)
17{
18 int button, defport;
19 Config *cfg = (Config *)data;
20 /*
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.
25 */
26 if (event == EVENT_REFRESH) {
27 for (button = 0; button < ctrl->radio.nbuttons; button++)
28 if (cfg->protocol == ctrl->radio.buttondata[button].i)
29 break;
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) {
39 defport = -1;
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;
44 }
45 if (defport > 0 && cfg->port != defport) {
46 cfg->port = defport;
47 dlg_refresh((union control *)ctrl->radio.context.p, dlg);
48 }
49 }
50 }
51}
52
17556692 53static void loggingbuttons_handler(union control *ctrl, void *dlg,
54 void *data, int event)
55{
56 int button;
57 Config *cfg = (Config *)data;
58 /* This function works just like the standard radio-button handler,
59 * but it has to fall back to "no logging" in situations where the
60 * configured logging type isn't applicable.
61 */
62 if (event == EVENT_REFRESH) {
63 for (button = 0; button < ctrl->radio.nbuttons; button++)
64 if (cfg->logtype == ctrl->radio.buttondata[button].i)
65 break;
66
67 /* We fell off the end, so we lack the configured logging type */
68 if (button == ctrl->radio.nbuttons) {
69 button=0;
70 cfg->logtype=LGTYP_NONE;
71 }
72 dlg_radiobutton_set(ctrl, dlg, button);
73 } else if (event == EVENT_VALCHANGE) {
74 button = dlg_radiobutton_get(ctrl, dlg);
75 assert(button >= 0 && button < ctrl->radio.nbuttons);
76 cfg->logtype = ctrl->radio.buttondata[button].i;
77 }
78}
79
fe8abbf4 80static void numeric_keypad_handler(union control *ctrl, void *dlg,
81 void *data, int event)
82{
83 int button;
84 Config *cfg = (Config *)data;
85 /*
86 * This function works much like the standard radio button
87 * handler, but it has to handle two fields in Config.
88 */
89 if (event == EVENT_REFRESH) {
90 if (cfg->nethack_keypad)
91 button = 2;
92 else if (cfg->app_keypad)
93 button = 1;
94 else
95 button = 0;
96 assert(button < ctrl->radio.nbuttons);
97 dlg_radiobutton_set(ctrl, dlg, button);
98 } else if (event == EVENT_VALCHANGE) {
99 button = dlg_radiobutton_get(ctrl, dlg);
100 assert(button >= 0 && button < ctrl->radio.nbuttons);
101 if (button == 2) {
102 cfg->app_keypad = FALSE;
103 cfg->nethack_keypad = TRUE;
104 } else {
105 cfg->app_keypad = (button != 0);
106 cfg->nethack_keypad = FALSE;
107 }
108 }
109}
110
111static void cipherlist_handler(union control *ctrl, void *dlg,
112 void *data, int event)
113{
114 Config *cfg = (Config *)data;
115 if (event == EVENT_REFRESH) {
116 int i;
117
118 static const struct { char *s; int c; } ciphers[] = {
119 { "3DES", CIPHER_3DES },
120 { "Blowfish", CIPHER_BLOWFISH },
121 { "DES", CIPHER_DES },
2e85c969 122 { "AES (SSH-2 only)", CIPHER_AES },
a2add208 123 { "Arcfour (SSH-2 only)", CIPHER_ARCFOUR },
fe8abbf4 124 { "-- warn below here --", CIPHER_WARN }
125 };
126
127 /* Set up the "selected ciphers" box. */
128 /* (cipherlist assumed to contain all ciphers) */
129 dlg_update_start(ctrl, dlg);
130 dlg_listbox_clear(ctrl, dlg);
131 for (i = 0; i < CIPHER_MAX; i++) {
132 int c = cfg->ssh_cipherlist[i];
133 int j;
134 char *cstr = NULL;
135 for (j = 0; j < (sizeof ciphers) / (sizeof ciphers[0]); j++) {
136 if (ciphers[j].c == c) {
137 cstr = ciphers[j].s;
138 break;
139 }
140 }
4eaff8d4 141 dlg_listbox_addwithid(ctrl, dlg, cstr, c);
fe8abbf4 142 }
143 dlg_update_done(ctrl, dlg);
144
145 } else if (event == EVENT_VALCHANGE) {
146 int i;
147
148 /* Update array to match the list box. */
149 for (i=0; i < CIPHER_MAX; i++)
150 cfg->ssh_cipherlist[i] = dlg_listbox_getid(ctrl, dlg, i);
151
152 }
153}
154
83e7d008 155static void kexlist_handler(union control *ctrl, void *dlg,
156 void *data, int event)
157{
158 Config *cfg = (Config *)data;
159 if (event == EVENT_REFRESH) {
160 int i;
161
162 static const struct { char *s; int k; } kexes[] = {
163 { "Diffie-Hellman group 1", KEX_DHGROUP1 },
164 { "Diffie-Hellman group 14", KEX_DHGROUP14 },
165 { "Diffie-Hellman group exchange", KEX_DHGEX },
166 { "-- warn below here --", KEX_WARN }
167 };
168
169 /* Set up the "kex preference" box. */
170 /* (kexlist assumed to contain all algorithms) */
171 dlg_update_start(ctrl, dlg);
172 dlg_listbox_clear(ctrl, dlg);
173 for (i = 0; i < KEX_MAX; i++) {
174 int k = cfg->ssh_kexlist[i];
175 int j;
176 char *kstr = NULL;
177 for (j = 0; j < (sizeof kexes) / (sizeof kexes[0]); j++) {
178 if (kexes[j].k == k) {
179 kstr = kexes[j].s;
180 break;
181 }
182 }
183 dlg_listbox_addwithid(ctrl, dlg, kstr, k);
184 }
185 dlg_update_done(ctrl, dlg);
186
187 } else if (event == EVENT_VALCHANGE) {
188 int i;
189
190 /* Update array to match the list box. */
191 for (i=0; i < KEX_MAX; i++)
192 cfg->ssh_kexlist[i] = dlg_listbox_getid(ctrl, dlg, i);
193
194 }
195}
196
fe8abbf4 197static void printerbox_handler(union control *ctrl, void *dlg,
198 void *data, int event)
199{
200 Config *cfg = (Config *)data;
201 if (event == EVENT_REFRESH) {
202 int nprinters, i;
203 printer_enum *pe;
204
205 dlg_update_start(ctrl, dlg);
0f915619 206 /*
207 * Some backends may wish to disable the drop-down list on
208 * this edit box. Be prepared for this.
209 */
210 if (ctrl->editbox.has_list) {
211 dlg_listbox_clear(ctrl, dlg);
212 dlg_listbox_add(ctrl, dlg, PRINTER_DISABLED_STRING);
213 pe = printer_start_enum(&nprinters);
214 for (i = 0; i < nprinters; i++)
215 dlg_listbox_add(ctrl, dlg, printer_get_name(pe, i));
216 printer_finish_enum(pe);
217 }
fe8abbf4 218 dlg_editbox_set(ctrl, dlg,
219 (*cfg->printer ? cfg->printer :
220 PRINTER_DISABLED_STRING));
221 dlg_update_done(ctrl, dlg);
222 } else if (event == EVENT_VALCHANGE) {
223 dlg_editbox_get(ctrl, dlg, cfg->printer, sizeof(cfg->printer));
224 if (!strcmp(cfg->printer, PRINTER_DISABLED_STRING))
225 *cfg->printer = '\0';
226 }
227}
228
229static void codepage_handler(union control *ctrl, void *dlg,
230 void *data, int event)
231{
232 Config *cfg = (Config *)data;
233 if (event == EVENT_REFRESH) {
234 int i;
d4413bd2 235 const char *cp;
fe8abbf4 236 dlg_update_start(ctrl, dlg);
237 strcpy(cfg->line_codepage,
238 cp_name(decode_codepage(cfg->line_codepage)));
239 dlg_listbox_clear(ctrl, dlg);
240 for (i = 0; (cp = cp_enumerate(i)) != NULL; i++)
241 dlg_listbox_add(ctrl, dlg, cp);
242 dlg_editbox_set(ctrl, dlg, cfg->line_codepage);
243 dlg_update_done(ctrl, dlg);
244 } else if (event == EVENT_VALCHANGE) {
245 dlg_editbox_get(ctrl, dlg, cfg->line_codepage,
246 sizeof(cfg->line_codepage));
247 strcpy(cfg->line_codepage,
248 cp_name(decode_codepage(cfg->line_codepage)));
249 }
250}
251
252static void sshbug_handler(union control *ctrl, void *dlg,
253 void *data, int event)
254{
255 if (event == EVENT_REFRESH) {
256 dlg_update_start(ctrl, dlg);
257 dlg_listbox_clear(ctrl, dlg);
4eaff8d4 258 dlg_listbox_addwithid(ctrl, dlg, "Auto", AUTO);
259 dlg_listbox_addwithid(ctrl, dlg, "Off", FORCE_OFF);
260 dlg_listbox_addwithid(ctrl, dlg, "On", FORCE_ON);
fe8abbf4 261 switch (*(int *)ATOFFSET(data, ctrl->listbox.context.i)) {
262 case AUTO: dlg_listbox_select(ctrl, dlg, 0); break;
263 case FORCE_OFF: dlg_listbox_select(ctrl, dlg, 1); break;
264 case FORCE_ON: dlg_listbox_select(ctrl, dlg, 2); break;
265 }
266 dlg_update_done(ctrl, dlg);
267 } else if (event == EVENT_SELCHANGE) {
268 int i = dlg_listbox_index(ctrl, dlg);
269 if (i < 0)
270 i = AUTO;
271 else
272 i = dlg_listbox_getid(ctrl, dlg, i);
273 *(int *)ATOFFSET(data, ctrl->listbox.context.i) = i;
274 }
275}
276
4e6d4091 277#define SAVEDSESSION_LEN 2048
278
fe8abbf4 279struct sessionsaver_data {
280 union control *editbox, *listbox, *loadbutton, *savebutton, *delbutton;
281 union control *okbutton, *cancelbutton;
12745e35 282 struct sesslist sesslist;
2e155f47 283 int midsession;
fe8abbf4 284};
285
286/*
287 * Helper function to load the session selected in the list box, if
288 * any, as this is done in more than one place below. Returns 0 for
289 * failure.
290 */
291static int load_selected_session(struct sessionsaver_data *ssd,
4e6d4091 292 char *savedsession,
fe8abbf4 293 void *dlg, Config *cfg)
294{
295 int i = dlg_listbox_index(ssd->listbox, dlg);
296 int isdef;
297 if (i < 0) {
298 dlg_beep(dlg);
299 return 0;
300 }
12745e35 301 isdef = !strcmp(ssd->sesslist.sessions[i], "Default Settings");
302 load_settings(ssd->sesslist.sessions[i], !isdef, cfg);
fe8abbf4 303 if (!isdef) {
12745e35 304 strncpy(savedsession, ssd->sesslist.sessions[i],
4e6d4091 305 SAVEDSESSION_LEN);
306 savedsession[SAVEDSESSION_LEN-1] = '\0';
fe8abbf4 307 } else {
4e6d4091 308 savedsession[0] = '\0';
fe8abbf4 309 }
310 dlg_refresh(NULL, dlg);
311 /* Restore the selection, which might have been clobbered by
312 * changing the value of the edit box. */
313 dlg_listbox_select(ssd->listbox, dlg, i);
314 return 1;
315}
316
317static void sessionsaver_handler(union control *ctrl, void *dlg,
318 void *data, int event)
319{
320 Config *cfg = (Config *)data;
321 struct sessionsaver_data *ssd =
322 (struct sessionsaver_data *)ctrl->generic.context.p;
4e6d4091 323 char *savedsession;
324
325 /*
326 * The first time we're called in a new dialog, we must
327 * allocate space to store the current contents of the saved
328 * session edit box (since it must persist even when we switch
329 * panels, but is not part of the Config).
330 */
56b9b9a7 331 if (!ssd->editbox) {
332 savedsession = NULL;
333 } else if (!dlg_get_privdata(ssd->editbox, dlg)) {
4e6d4091 334 savedsession = (char *)
335 dlg_alloc_privdata(ssd->editbox, dlg, SAVEDSESSION_LEN);
336 savedsession[0] = '\0';
337 } else {
338 savedsession = dlg_get_privdata(ssd->editbox, dlg);
339 }
fe8abbf4 340
341 if (event == EVENT_REFRESH) {
342 if (ctrl == ssd->editbox) {
4e6d4091 343 dlg_editbox_set(ctrl, dlg, savedsession);
fe8abbf4 344 } else if (ctrl == ssd->listbox) {
345 int i;
346 dlg_update_start(ctrl, dlg);
347 dlg_listbox_clear(ctrl, dlg);
12745e35 348 for (i = 0; i < ssd->sesslist.nsessions; i++)
349 dlg_listbox_add(ctrl, dlg, ssd->sesslist.sessions[i]);
fe8abbf4 350 dlg_update_done(ctrl, dlg);
351 }
352 } else if (event == EVENT_VALCHANGE) {
353 if (ctrl == ssd->editbox) {
4e6d4091 354 dlg_editbox_get(ctrl, dlg, savedsession,
355 SAVEDSESSION_LEN);
fe8abbf4 356 }
357 } else if (event == EVENT_ACTION) {
2e155f47 358 if (!ssd->midsession &&
359 (ctrl == ssd->listbox ||
360 (ssd->loadbutton && ctrl == ssd->loadbutton))) {
fe8abbf4 361 /*
362 * The user has double-clicked a session, or hit Load.
363 * We must load the selected session, and then
364 * terminate the configuration dialog _if_ there was a
365 * double-click on the list box _and_ that session
366 * contains a hostname.
367 */
4e6d4091 368 if (load_selected_session(ssd, savedsession, dlg, cfg) &&
fe8abbf4 369 (ctrl == ssd->listbox && cfg->host[0])) {
370 dlg_end(dlg, 1); /* it's all over, and succeeded */
371 }
372 } else if (ctrl == ssd->savebutton) {
4e6d4091 373 int isdef = !strcmp(savedsession, "Default Settings");
374 if (!savedsession[0]) {
8b0cb5aa 375 int i = dlg_listbox_index(ssd->listbox, dlg);
fe8abbf4 376 if (i < 0) {
377 dlg_beep(dlg);
378 return;
379 }
12745e35 380 isdef = !strcmp(ssd->sesslist.sessions[i], "Default Settings");
fe8abbf4 381 if (!isdef) {
12745e35 382 strncpy(savedsession, ssd->sesslist.sessions[i],
4e6d4091 383 SAVEDSESSION_LEN);
384 savedsession[SAVEDSESSION_LEN-1] = '\0';
fe8abbf4 385 } else {
4e6d4091 386 savedsession[0] = '\0';
fe8abbf4 387 }
388 }
3f935d5b 389 {
390 char *errmsg = save_settings(savedsession, !isdef, cfg);
391 if (errmsg) {
392 dlg_error_msg(dlg, errmsg);
393 sfree(errmsg);
394 }
395 }
12745e35 396 get_sesslist(&ssd->sesslist, FALSE);
397 get_sesslist(&ssd->sesslist, TRUE);
fe8abbf4 398 dlg_refresh(ssd->editbox, dlg);
399 dlg_refresh(ssd->listbox, dlg);
2e155f47 400 } else if (!ssd->midsession &&
401 ssd->delbutton && ctrl == ssd->delbutton) {
6f87d111 402 int i = dlg_listbox_index(ssd->listbox, dlg);
fe8abbf4 403 if (i <= 0) {
404 dlg_beep(dlg);
405 } else {
12745e35 406 del_settings(ssd->sesslist.sessions[i]);
407 get_sesslist(&ssd->sesslist, FALSE);
408 get_sesslist(&ssd->sesslist, TRUE);
fe8abbf4 409 dlg_refresh(ssd->listbox, dlg);
410 }
411 } else if (ctrl == ssd->okbutton) {
2e155f47 412 if (ssd->midsession) {
56b9b9a7 413 /* In a mid-session Change Settings, Apply is always OK. */
414 dlg_end(dlg, 1);
415 return;
416 }
fe8abbf4 417 /*
418 * Annoying special case. If the `Open' button is
419 * pressed while no host name is currently set, _and_
420 * the session list previously had the focus, _and_
421 * there was a session selected in that which had a
422 * valid host name in it, then load it and go.
423 */
0bd8d76d 424 if (dlg_last_focused(ctrl, dlg) == ssd->listbox && !*cfg->host) {
fe8abbf4 425 Config cfg2;
4e6d4091 426 if (!load_selected_session(ssd, savedsession, dlg, &cfg2)) {
fe8abbf4 427 dlg_beep(dlg);
428 return;
429 }
430 /* If at this point we have a valid session, go! */
431 if (*cfg2.host) {
432 *cfg = cfg2; /* structure copy */
04c52f10 433 cfg->remote_cmd_ptr = NULL;
fe8abbf4 434 dlg_end(dlg, 1);
435 } else
436 dlg_beep(dlg);
431c0a12 437 return;
fe8abbf4 438 }
439
440 /*
441 * Otherwise, do the normal thing: if we have a valid
442 * session, get going.
443 */
444 if (*cfg->host) {
445 dlg_end(dlg, 1);
446 } else
447 dlg_beep(dlg);
448 } else if (ctrl == ssd->cancelbutton) {
449 dlg_end(dlg, 0);
450 }
451 }
452}
453
454struct charclass_data {
455 union control *listbox, *editbox, *button;
456};
457
458static void charclass_handler(union control *ctrl, void *dlg,
459 void *data, int event)
460{
461 Config *cfg = (Config *)data;
462 struct charclass_data *ccd =
463 (struct charclass_data *)ctrl->generic.context.p;
464
465 if (event == EVENT_REFRESH) {
466 if (ctrl == ccd->listbox) {
467 int i;
468 dlg_update_start(ctrl, dlg);
469 dlg_listbox_clear(ctrl, dlg);
470 for (i = 0; i < 128; i++) {
471 char str[100];
472 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
473 (i >= 0x21 && i != 0x7F) ? i : ' ', cfg->wordness[i]);
474 dlg_listbox_add(ctrl, dlg, str);
475 }
476 dlg_update_done(ctrl, dlg);
477 }
478 } else if (event == EVENT_ACTION) {
479 if (ctrl == ccd->button) {
480 char str[100];
481 int i, n;
482 dlg_editbox_get(ccd->editbox, dlg, str, sizeof(str));
483 n = atoi(str);
484 for (i = 0; i < 128; i++) {
485 if (dlg_listbox_issel(ccd->listbox, dlg, i))
486 cfg->wordness[i] = n;
487 }
488 dlg_refresh(ccd->listbox, dlg);
489 }
490 }
491}
492
493struct colour_data {
18c2f87c 494 union control *listbox, *redit, *gedit, *bedit, *button;
fe8abbf4 495};
496
497static const char *const colours[] = {
498 "Default Foreground", "Default Bold Foreground",
499 "Default Background", "Default Bold Background",
500 "Cursor Text", "Cursor Colour",
501 "ANSI Black", "ANSI Black Bold",
502 "ANSI Red", "ANSI Red Bold",
503 "ANSI Green", "ANSI Green Bold",
504 "ANSI Yellow", "ANSI Yellow Bold",
505 "ANSI Blue", "ANSI Blue Bold",
506 "ANSI Magenta", "ANSI Magenta Bold",
507 "ANSI Cyan", "ANSI Cyan Bold",
508 "ANSI White", "ANSI White Bold"
509};
510
511static void colour_handler(union control *ctrl, void *dlg,
512 void *data, int event)
513{
514 Config *cfg = (Config *)data;
515 struct colour_data *cd =
516 (struct colour_data *)ctrl->generic.context.p;
517 int update = FALSE, r, g, b;
518
519 if (event == EVENT_REFRESH) {
520 if (ctrl == cd->listbox) {
521 int i;
522 dlg_update_start(ctrl, dlg);
523 dlg_listbox_clear(ctrl, dlg);
524 for (i = 0; i < lenof(colours); i++)
525 dlg_listbox_add(ctrl, dlg, colours[i]);
526 dlg_update_done(ctrl, dlg);
18c2f87c 527 dlg_editbox_set(cd->redit, dlg, "");
528 dlg_editbox_set(cd->gedit, dlg, "");
529 dlg_editbox_set(cd->bedit, dlg, "");
fe8abbf4 530 }
531 } else if (event == EVENT_SELCHANGE) {
532 if (ctrl == cd->listbox) {
533 /* The user has selected a colour. Update the RGB text. */
534 int i = dlg_listbox_index(ctrl, dlg);
535 if (i < 0) {
536 dlg_beep(dlg);
537 return;
538 }
539 r = cfg->colours[i][0];
540 g = cfg->colours[i][1];
541 b = cfg->colours[i][2];
542 update = TRUE;
543 }
18c2f87c 544 } else if (event == EVENT_VALCHANGE) {
545 if (ctrl == cd->redit || ctrl == cd->gedit || ctrl == cd->bedit) {
546 /* The user has changed the colour using the edit boxes. */
547 char buf[80];
548 int i, cval;
549
550 dlg_editbox_get(ctrl, dlg, buf, lenof(buf));
551 cval = atoi(buf) & 255;
552
553 i = dlg_listbox_index(cd->listbox, dlg);
554 if (i >= 0) {
555 if (ctrl == cd->redit)
556 cfg->colours[i][0] = cval;
557 else if (ctrl == cd->gedit)
558 cfg->colours[i][1] = cval;
559 else if (ctrl == cd->bedit)
560 cfg->colours[i][2] = cval;
561 }
562 }
fe8abbf4 563 } else if (event == EVENT_ACTION) {
564 if (ctrl == cd->button) {
565 int i = dlg_listbox_index(cd->listbox, dlg);
566 if (i < 0) {
567 dlg_beep(dlg);
568 return;
569 }
570 /*
571 * Start a colour selector, which will send us an
572 * EVENT_CALLBACK when it's finished and allow us to
573 * pick up the results.
574 */
575 dlg_coloursel_start(ctrl, dlg,
576 cfg->colours[i][0],
577 cfg->colours[i][1],
578 cfg->colours[i][2]);
579 }
580 } else if (event == EVENT_CALLBACK) {
581 if (ctrl == cd->button) {
582 int i = dlg_listbox_index(cd->listbox, dlg);
583 /*
584 * Collect the results of the colour selector. Will
585 * return nonzero on success, or zero if the colour
586 * selector did nothing (user hit Cancel, for example).
587 */
588 if (dlg_coloursel_results(ctrl, dlg, &r, &g, &b)) {
589 cfg->colours[i][0] = r;
590 cfg->colours[i][1] = g;
591 cfg->colours[i][2] = b;
592 update = TRUE;
593 }
594 }
595 }
596
597 if (update) {
598 char buf[40];
18c2f87c 599 sprintf(buf, "%d", r); dlg_editbox_set(cd->redit, dlg, buf);
600 sprintf(buf, "%d", g); dlg_editbox_set(cd->gedit, dlg, buf);
601 sprintf(buf, "%d", b); dlg_editbox_set(cd->bedit, dlg, buf);
fe8abbf4 602 }
603}
604
c6ccd5c2 605struct ttymodes_data {
606 union control *modelist, *valradio, *valbox;
607 union control *addbutton, *rembutton, *listbox;
608};
609
610static void ttymodes_handler(union control *ctrl, void *dlg,
611 void *data, int event)
612{
613 Config *cfg = (Config *)data;
614 struct ttymodes_data *td =
615 (struct ttymodes_data *)ctrl->generic.context.p;
616
617 if (event == EVENT_REFRESH) {
618 if (ctrl == td->listbox) {
619 char *p = cfg->ttymodes;
620 dlg_update_start(ctrl, dlg);
621 dlg_listbox_clear(ctrl, dlg);
622 while (*p) {
623 int tabpos = strchr(p, '\t') - p;
624 char *disp = dupprintf("%.*s\t%s", tabpos, p,
625 (p[tabpos+1] == 'A') ? "(auto)" :
626 p+tabpos+2);
627 dlg_listbox_add(ctrl, dlg, disp);
628 p += strlen(p) + 1;
629 sfree(disp);
630 }
631 dlg_update_done(ctrl, dlg);
632 } else if (ctrl == td->modelist) {
633 int i;
634 dlg_update_start(ctrl, dlg);
635 dlg_listbox_clear(ctrl, dlg);
636 for (i = 0; ttymodes[i]; i++)
637 dlg_listbox_add(ctrl, dlg, ttymodes[i]);
638 dlg_listbox_select(ctrl, dlg, 0); /* *shrug* */
639 dlg_update_done(ctrl, dlg);
640 } else if (ctrl == td->valradio) {
641 dlg_radiobutton_set(ctrl, dlg, 0);
642 }
643 } else if (event == EVENT_ACTION) {
644 if (ctrl == td->addbutton) {
645 int ind = dlg_listbox_index(td->modelist, dlg);
646 if (ind >= 0) {
647 char type = dlg_radiobutton_get(td->valradio, dlg) ? 'V' : 'A';
648 int slen, left;
649 char *p, str[lenof(cfg->ttymodes)];
650 /* Construct new entry */
651 memset(str, 0, lenof(str));
652 strncpy(str, ttymodes[ind], lenof(str)-3);
653 slen = strlen(str);
654 str[slen] = '\t';
655 str[slen+1] = type;
656 slen += 2;
657 if (type == 'V') {
658 dlg_editbox_get(td->valbox, dlg, str+slen, lenof(str)-slen);
659 }
660 /* Find end of list, deleting any existing instance */
661 p = cfg->ttymodes;
662 left = lenof(cfg->ttymodes);
663 while (*p) {
664 int t = strchr(p, '\t') - p;
665 if (t == strlen(ttymodes[ind]) &&
666 strncmp(p, ttymodes[ind], t) == 0) {
667 memmove(p, p+strlen(p)+1, left - (strlen(p)+1));
668 continue;
669 }
670 left -= strlen(p) + 1;
671 p += strlen(p) + 1;
672 }
673 /* Append new entry */
674 memset(p, 0, left);
675 strncpy(p, str, left - 2);
676 dlg_refresh(td->listbox, dlg);
677 } else
678 dlg_beep(dlg);
679 } else if (ctrl == td->rembutton) {
680 char *p = cfg->ttymodes;
681 int i = 0, len = lenof(cfg->ttymodes);
682 while (*p) {
683 if (dlg_listbox_issel(td->listbox, dlg, i)) {
684 memmove(p, p+strlen(p)+1, len - (strlen(p)+1));
685 i++;
686 continue;
687 }
688 len -= strlen(p) + 1;
689 p += strlen(p) + 1;
690 i++;
691 }
692 memset(p, 0, lenof(cfg->ttymodes) - len);
693 dlg_refresh(td->listbox, dlg);
694 }
695 }
696}
697
fe8abbf4 698struct environ_data {
699 union control *varbox, *valbox, *addbutton, *rembutton, *listbox;
700};
701
702static void environ_handler(union control *ctrl, void *dlg,
703 void *data, int event)
704{
705 Config *cfg = (Config *)data;
706 struct environ_data *ed =
707 (struct environ_data *)ctrl->generic.context.p;
708
709 if (event == EVENT_REFRESH) {
710 if (ctrl == ed->listbox) {
711 char *p = cfg->environmt;
712 dlg_update_start(ctrl, dlg);
713 dlg_listbox_clear(ctrl, dlg);
714 while (*p) {
715 dlg_listbox_add(ctrl, dlg, p);
716 p += strlen(p) + 1;
717 }
718 dlg_update_done(ctrl, dlg);
719 }
720 } else if (event == EVENT_ACTION) {
721 if (ctrl == ed->addbutton) {
722 char str[sizeof(cfg->environmt)];
723 char *p;
724 dlg_editbox_get(ed->varbox, dlg, str, sizeof(str)-1);
725 if (!*str) {
726 dlg_beep(dlg);
727 return;
728 }
729 p = str + strlen(str);
730 *p++ = '\t';
731 dlg_editbox_get(ed->valbox, dlg, p, sizeof(str)-1 - (p - str));
732 if (!*p) {
733 dlg_beep(dlg);
734 return;
735 }
736 p = cfg->environmt;
737 while (*p) {
738 while (*p)
739 p++;
740 p++;
741 }
742 if ((p - cfg->environmt) + strlen(str) + 2 <
743 sizeof(cfg->environmt)) {
744 strcpy(p, str);
745 p[strlen(str) + 1] = '\0';
746 dlg_listbox_add(ed->listbox, dlg, str);
747 dlg_editbox_set(ed->varbox, dlg, "");
748 dlg_editbox_set(ed->valbox, dlg, "");
749 } else {
750 dlg_error_msg(dlg, "Environment too big");
751 }
752 } else if (ctrl == ed->rembutton) {
753 int i = dlg_listbox_index(ed->listbox, dlg);
754 if (i < 0) {
755 dlg_beep(dlg);
756 } else {
757 char *p, *q;
758
759 dlg_listbox_del(ed->listbox, dlg, i);
760 p = cfg->environmt;
761 while (i > 0) {
762 if (!*p)
763 goto disaster;
764 while (*p)
765 p++;
766 p++;
767 i--;
768 }
769 q = p;
770 if (!*p)
771 goto disaster;
772 while (*p)
773 p++;
774 p++;
775 while (*p) {
776 while (*p)
777 *q++ = *p++;
778 *q++ = *p++;
779 }
780 *q = '\0';
781 disaster:;
782 }
783 }
784 }
785}
786
787struct portfwd_data {
788 union control *addbutton, *rembutton, *listbox;
789 union control *sourcebox, *destbox, *direction;
89adc0e2 790#ifndef NO_IPV6
05581745 791 union control *addressfamily;
89adc0e2 792#endif
fe8abbf4 793};
794
795static void portfwd_handler(union control *ctrl, void *dlg,
796 void *data, int event)
797{
798 Config *cfg = (Config *)data;
799 struct portfwd_data *pfd =
800 (struct portfwd_data *)ctrl->generic.context.p;
801
802 if (event == EVENT_REFRESH) {
803 if (ctrl == pfd->listbox) {
804 char *p = cfg->portfwd;
805 dlg_update_start(ctrl, dlg);
806 dlg_listbox_clear(ctrl, dlg);
807 while (*p) {
808 dlg_listbox_add(ctrl, dlg, p);
809 p += strlen(p) + 1;
810 }
811 dlg_update_done(ctrl, dlg);
07e4d76d 812 } else if (ctrl == pfd->direction) {
813 /*
814 * Default is Local.
815 */
816 dlg_radiobutton_set(ctrl, dlg, 0);
89adc0e2 817#ifndef NO_IPV6
818 } else if (ctrl == pfd->addressfamily) {
05581745 819 dlg_radiobutton_set(ctrl, dlg, 0);
89adc0e2 820#endif
fe8abbf4 821 }
822 } else if (event == EVENT_ACTION) {
823 if (ctrl == pfd->addbutton) {
824 char str[sizeof(cfg->portfwd)];
825 char *p;
05581745 826 int i, type;
827 int whichbutton;
828
829 i = 0;
89adc0e2 830#ifndef NO_IPV6
05581745 831 whichbutton = dlg_radiobutton_get(pfd->addressfamily, dlg);
832 if (whichbutton == 1)
833 str[i++] = '4';
834 else if (whichbutton == 2)
835 str[i++] = '6';
89adc0e2 836#endif
05581745 837
838 whichbutton = dlg_radiobutton_get(pfd->direction, dlg);
820ebe3b 839 if (whichbutton == 0)
05581745 840 type = 'L';
820ebe3b 841 else if (whichbutton == 1)
05581745 842 type = 'R';
820ebe3b 843 else
05581745 844 type = 'D';
845 str[i++] = type;
846
847 dlg_editbox_get(pfd->sourcebox, dlg, str+i, sizeof(str) - i);
94042edc 848 if (!str[i]) {
fe8abbf4 849 dlg_error_msg(dlg, "You need to specify a source port number");
850 return;
851 }
852 p = str + strlen(str);
05581745 853 if (type != 'D') {
820ebe3b 854 *p++ = '\t';
855 dlg_editbox_get(pfd->destbox, dlg, p,
e49c58ed 856 sizeof(str) - (p - str));
820ebe3b 857 if (!*p || !strchr(p, ':')) {
858 dlg_error_msg(dlg,
859 "You need to specify a destination address\n"
860 "in the form \"host.name:port\"");
861 return;
862 }
863 } else
864 *p = '\0';
fe8abbf4 865 p = cfg->portfwd;
866 while (*p) {
867 while (*p)
868 p++;
869 p++;
870 }
e49c58ed 871 if ((p - cfg->portfwd) + strlen(str) + 2 <=
fe8abbf4 872 sizeof(cfg->portfwd)) {
873 strcpy(p, str);
874 p[strlen(str) + 1] = '\0';
875 dlg_listbox_add(pfd->listbox, dlg, str);
876 dlg_editbox_set(pfd->sourcebox, dlg, "");
877 dlg_editbox_set(pfd->destbox, dlg, "");
878 } else {
879 dlg_error_msg(dlg, "Too many forwardings");
880 }
881 } else if (ctrl == pfd->rembutton) {
882 int i = dlg_listbox_index(pfd->listbox, dlg);
883 if (i < 0)
884 dlg_beep(dlg);
885 else {
886 char *p, *q;
887
888 dlg_listbox_del(pfd->listbox, dlg, i);
889 p = cfg->portfwd;
890 while (i > 0) {
891 if (!*p)
892 goto disaster2;
893 while (*p)
894 p++;
895 p++;
896 i--;
897 }
898 q = p;
899 if (!*p)
900 goto disaster2;
901 while (*p)
902 p++;
903 p++;
904 while (*p) {
905 while (*p)
906 *q++ = *p++;
907 *q++ = *p++;
908 }
909 *q = '\0';
910 disaster2:;
911 }
912 }
913 }
914}
915
12745e35 916void setup_config_box(struct controlbox *b, int midsession,
917 int protocol, int protcfginfo)
fe8abbf4 918{
919 struct controlset *s;
920 struct sessionsaver_data *ssd;
921 struct charclass_data *ccd;
922 struct colour_data *cd;
c6ccd5c2 923 struct ttymodes_data *td;
fe8abbf4 924 struct environ_data *ed;
925 struct portfwd_data *pfd;
926 union control *c;
f6f450e2 927 char *str;
fe8abbf4 928
929 ssd = (struct sessionsaver_data *)
930 ctrl_alloc(b, sizeof(struct sessionsaver_data));
56b9b9a7 931 memset(ssd, 0, sizeof(*ssd));
2e155f47 932 ssd->midsession = midsession;
fe8abbf4 933
934 /*
935 * The standard panel that appears at the bottom of all panels:
936 * Open, Cancel, Apply etc.
937 */
938 s = ctrl_getset(b, "", "", "");
939 ctrl_columns(s, 5, 20, 20, 20, 20, 20);
940 ssd->okbutton = ctrl_pushbutton(s,
941 (midsession ? "Apply" : "Open"),
942 (char)(midsession ? 'a' : 'o'),
943 HELPCTX(no_help),
944 sessionsaver_handler, P(ssd));
945 ssd->okbutton->button.isdefault = TRUE;
946 ssd->okbutton->generic.column = 3;
947 ssd->cancelbutton = ctrl_pushbutton(s, "Cancel", 'c', HELPCTX(no_help),
948 sessionsaver_handler, P(ssd));
0bd8d76d 949 ssd->cancelbutton->button.iscancel = TRUE;
fe8abbf4 950 ssd->cancelbutton->generic.column = 4;
951 /* We carefully don't close the 5-column part, so that platform-
952 * specific add-ons can put extra buttons alongside Open and Cancel. */
953
954 /*
955 * The Session panel.
956 */
f6f450e2 957 str = dupprintf("Basic options for your %s session", appname);
958 ctrl_settitle(b, "Session", str);
959 sfree(str);
fe8abbf4 960
961 if (!midsession) {
962 s = ctrl_getset(b, "Session", "hostport",
963 "Specify your connection by host name or IP address");
964 ctrl_columns(s, 2, 75, 25);
965 c = ctrl_editbox(s, "Host Name (or IP address)", 'n', 100,
966 HELPCTX(session_hostname),
967 dlg_stdeditbox_handler, I(offsetof(Config,host)),
968 I(sizeof(((Config *)0)->host)));
969 c->generic.column = 0;
970 c = ctrl_editbox(s, "Port", 'p', 100, HELPCTX(session_hostname),
971 dlg_stdeditbox_handler,
972 I(offsetof(Config,port)), I(-1));
973 c->generic.column = 1;
974 ctrl_columns(s, 1, 100);
d9b15094 975 if (backends[3].name == NULL) {
fe8abbf4 976 ctrl_radiobuttons(s, "Protocol:", NO_SHORTCUT, 3,
977 HELPCTX(session_hostname),
978 protocolbuttons_handler, P(c),
979 "Raw", 'r', I(PROT_RAW),
980 "Telnet", 't', I(PROT_TELNET),
981 "Rlogin", 'i', I(PROT_RLOGIN),
982 NULL);
983 } else {
984 ctrl_radiobuttons(s, "Protocol:", NO_SHORTCUT, 4,
985 HELPCTX(session_hostname),
986 protocolbuttons_handler, P(c),
987 "Raw", 'r', I(PROT_RAW),
988 "Telnet", 't', I(PROT_TELNET),
989 "Rlogin", 'i', I(PROT_RLOGIN),
990 "SSH", 's', I(PROT_SSH),
991 NULL);
992 }
fe8abbf4 993 }
994
48c4dd7c 995 /*
996 * The Load/Save panel is available even in mid-session.
997 */
998 s = ctrl_getset(b, "Session", "savedsessions",
59b8cd5a 999 midsession ? "Save the current session settings" :
48c4dd7c 1000 "Load, save or delete a stored session");
1001 ctrl_columns(s, 2, 75, 25);
12745e35 1002 get_sesslist(&ssd->sesslist, TRUE);
48c4dd7c 1003 ssd->editbox = ctrl_editbox(s, "Saved Sessions", 'e', 100,
1004 HELPCTX(session_saved),
1005 sessionsaver_handler, P(ssd), P(NULL));
1006 ssd->editbox->generic.column = 0;
1007 /* Reset columns so that the buttons are alongside the list, rather
1008 * than alongside that edit box. */
1009 ctrl_columns(s, 1, 100);
1010 ctrl_columns(s, 2, 75, 25);
1011 ssd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1012 HELPCTX(session_saved),
1013 sessionsaver_handler, P(ssd));
1014 ssd->listbox->generic.column = 0;
1015 ssd->listbox->listbox.height = 7;
2e155f47 1016 if (!midsession) {
1017 ssd->loadbutton = ctrl_pushbutton(s, "Load", 'l',
1018 HELPCTX(session_saved),
1019 sessionsaver_handler, P(ssd));
1020 ssd->loadbutton->generic.column = 1;
1021 } else {
1022 /* We can't offer the Load button mid-session, as it would allow the
1023 * user to load and subsequently save settings they can't see. (And
1024 * also change otherwise immutable settings underfoot; that probably
1025 * shouldn't be a problem, but.) */
1026 ssd->loadbutton = NULL;
1027 }
1028 /* "Save" button is permitted mid-session. */
48c4dd7c 1029 ssd->savebutton = ctrl_pushbutton(s, "Save", 'v',
1030 HELPCTX(session_saved),
1031 sessionsaver_handler, P(ssd));
1032 ssd->savebutton->generic.column = 1;
2e155f47 1033 if (!midsession) {
1034 ssd->delbutton = ctrl_pushbutton(s, "Delete", 'd',
1035 HELPCTX(session_saved),
1036 sessionsaver_handler, P(ssd));
1037 ssd->delbutton->generic.column = 1;
1038 } else {
1039 /* Disable the Delete button mid-session too, for UI consistency. */
1040 ssd->delbutton = NULL;
1041 }
48c4dd7c 1042 ctrl_columns(s, 1, 100);
1043
fe8abbf4 1044 s = ctrl_getset(b, "Session", "otheropts", NULL);
1045 c = ctrl_radiobuttons(s, "Close window on exit:", 'w', 4,
1046 HELPCTX(session_coe),
1047 dlg_stdradiobutton_handler,
1048 I(offsetof(Config, close_on_exit)),
1049 "Always", I(FORCE_ON),
1050 "Never", I(FORCE_OFF),
1051 "Only on clean exit", I(AUTO), NULL);
1052
1053 /*
1054 * The Session/Logging panel.
1055 */
1056 ctrl_settitle(b, "Session/Logging", "Options controlling session logging");
1057
1058 s = ctrl_getset(b, "Session/Logging", "main", NULL);
3e547dd8 1059 /*
1060 * The logging buttons change depending on whether SSH packet
1061 * logging can sensibly be available.
1062 */
1063 {
1064 char *sshlogname;
1065 if ((midsession && protocol == PROT_SSH) ||
1066 (!midsession && backends[3].name != NULL))
1067 sshlogname = "Log SSH packet data";
1068 else
1069 sshlogname = NULL; /* this will disable the button */
1070 ctrl_radiobuttons(s, "Session logging:", NO_SHORTCUT, 1,
1071 HELPCTX(logging_main),
17556692 1072 loggingbuttons_handler,
3e547dd8 1073 I(offsetof(Config, logtype)),
1074 "Logging turned off completely", 't', I(LGTYP_NONE),
1075 "Log printable output only", 'p', I(LGTYP_ASCII),
1076 "Log all session output", 'l', I(LGTYP_DEBUG),
1077 sshlogname, 's', I(LGTYP_PACKETS),
1078 NULL);
1079 }
fe8abbf4 1080 ctrl_filesel(s, "Log file name:", 'f',
1081 NULL, TRUE, "Select session log file name",
1082 HELPCTX(logging_filename),
1083 dlg_stdfilesel_handler, I(offsetof(Config, logfilename)));
1084 ctrl_text(s, "(Log file name can contain &Y, &M, &D for date,"
1085 " &T for time, and &H for host name)",
1086 HELPCTX(logging_filename));
1087 ctrl_radiobuttons(s, "What to do if the log file already exists:", 'e', 1,
1088 HELPCTX(logging_exists),
1089 dlg_stdradiobutton_handler, I(offsetof(Config,logxfovr)),
1090 "Always overwrite it", I(LGXF_OVR),
1091 "Always append to the end of it", I(LGXF_APN),
1092 "Ask the user every time", I(LGXF_ASK), NULL);
6d60c791 1093 ctrl_checkbox(s, "Flush log file frequently", 'u',
1094 HELPCTX(logging_flush),
1095 dlg_stdcheckbox_handler, I(offsetof(Config,logflush)));
fe8abbf4 1096
9a10ecf4 1097 if ((midsession && protocol == PROT_SSH) ||
1098 (!midsession && backends[3].name != NULL)) {
1099 s = ctrl_getset(b, "Session/Logging", "ssh",
1100 "Options specific to SSH packet logging");
1101 ctrl_checkbox(s, "Omit known password fields", 'k',
1102 HELPCTX(logging_ssh_omit_password),
1103 dlg_stdcheckbox_handler, I(offsetof(Config,logomitpass)));
1104 ctrl_checkbox(s, "Omit session data", 'd',
1105 HELPCTX(logging_ssh_omit_data),
1106 dlg_stdcheckbox_handler, I(offsetof(Config,logomitdata)));
1107 }
1108
fe8abbf4 1109 /*
1110 * The Terminal panel.
1111 */
1112 ctrl_settitle(b, "Terminal", "Options controlling the terminal emulation");
1113
1114 s = ctrl_getset(b, "Terminal", "general", "Set various terminal options");
1115 ctrl_checkbox(s, "Auto wrap mode initially on", 'w',
1116 HELPCTX(terminal_autowrap),
1117 dlg_stdcheckbox_handler, I(offsetof(Config,wrap_mode)));
1118 ctrl_checkbox(s, "DEC Origin Mode initially on", 'd',
1119 HELPCTX(terminal_decom),
1120 dlg_stdcheckbox_handler, I(offsetof(Config,dec_om)));
1121 ctrl_checkbox(s, "Implicit CR in every LF", 'r',
1122 HELPCTX(terminal_lfhascr),
1123 dlg_stdcheckbox_handler, I(offsetof(Config,lfhascr)));
1124 ctrl_checkbox(s, "Use background colour to erase screen", 'e',
1125 HELPCTX(terminal_bce),
1126 dlg_stdcheckbox_handler, I(offsetof(Config,bce)));
1127 ctrl_checkbox(s, "Enable blinking text", 'n',
1128 HELPCTX(terminal_blink),
1129 dlg_stdcheckbox_handler, I(offsetof(Config,blinktext)));
1130 ctrl_editbox(s, "Answerback to ^E:", 's', 100,
1131 HELPCTX(terminal_answerback),
1132 dlg_stdeditbox_handler, I(offsetof(Config,answerback)),
1133 I(sizeof(((Config *)0)->answerback)));
1134
1135 s = ctrl_getset(b, "Terminal", "ldisc", "Line discipline options");
1136 ctrl_radiobuttons(s, "Local echo:", 'l', 3,
1137 HELPCTX(terminal_localecho),
1138 dlg_stdradiobutton_handler,I(offsetof(Config,localecho)),
1139 "Auto", I(AUTO),
1140 "Force on", I(FORCE_ON),
1141 "Force off", I(FORCE_OFF), NULL);
1142 ctrl_radiobuttons(s, "Local line editing:", 't', 3,
1143 HELPCTX(terminal_localedit),
1144 dlg_stdradiobutton_handler,I(offsetof(Config,localedit)),
1145 "Auto", I(AUTO),
1146 "Force on", I(FORCE_ON),
1147 "Force off", I(FORCE_OFF), NULL);
1148
1149 s = ctrl_getset(b, "Terminal", "printing", "Remote-controlled printing");
1150 ctrl_combobox(s, "Printer to send ANSI printer output to:", 'p', 100,
1151 HELPCTX(terminal_printing),
1152 printerbox_handler, P(NULL), P(NULL));
1153
1154 /*
1155 * The Terminal/Keyboard panel.
1156 */
1157 ctrl_settitle(b, "Terminal/Keyboard",
1158 "Options controlling the effects of keys");
1159
1160 s = ctrl_getset(b, "Terminal/Keyboard", "mappings",
1161 "Change the sequences sent by:");
1162 ctrl_radiobuttons(s, "The Backspace key", 'b', 2,
1163 HELPCTX(keyboard_backspace),
1164 dlg_stdradiobutton_handler,
1165 I(offsetof(Config, bksp_is_delete)),
1166 "Control-H", I(0), "Control-? (127)", I(1), NULL);
1167 ctrl_radiobuttons(s, "The Home and End keys", 'e', 2,
1168 HELPCTX(keyboard_homeend),
1169 dlg_stdradiobutton_handler,
1170 I(offsetof(Config, rxvt_homeend)),
1171 "Standard", I(0), "rxvt", I(1), NULL);
1172 ctrl_radiobuttons(s, "The Function keys and keypad", 'f', 3,
1173 HELPCTX(keyboard_funkeys),
1174 dlg_stdradiobutton_handler,
1175 I(offsetof(Config, funky_type)),
1176 "ESC[n~", I(0), "Linux", I(1), "Xterm R6", I(2),
1177 "VT400", I(3), "VT100+", I(4), "SCO", I(5), NULL);
1178
1179 s = ctrl_getset(b, "Terminal/Keyboard", "appkeypad",
1180 "Application keypad settings:");
1181 ctrl_radiobuttons(s, "Initial state of cursor keys:", 'r', 3,
1182 HELPCTX(keyboard_appcursor),
1183 dlg_stdradiobutton_handler,
1184 I(offsetof(Config, app_cursor)),
1185 "Normal", I(0), "Application", I(1), NULL);
1186 ctrl_radiobuttons(s, "Initial state of numeric keypad:", 'n', 3,
1187 HELPCTX(keyboard_appkeypad),
1188 numeric_keypad_handler, P(NULL),
1189 "Normal", I(0), "Application", I(1), "NetHack", I(2),
1190 NULL);
1191
1192 /*
1193 * The Terminal/Bell panel.
1194 */
1195 ctrl_settitle(b, "Terminal/Bell",
1196 "Options controlling the terminal bell");
1197
1198 s = ctrl_getset(b, "Terminal/Bell", "style", "Set the style of bell");
1199 ctrl_radiobuttons(s, "Action to happen when a bell occurs:", 'b', 1,
1200 HELPCTX(bell_style),
1201 dlg_stdradiobutton_handler, I(offsetof(Config, beep)),
1202 "None (bell disabled)", I(BELL_DISABLED),
1203 "Make default system alert sound", I(BELL_DEFAULT),
1204 "Visual bell (flash window)", I(BELL_VISUAL), NULL);
1205
1206 s = ctrl_getset(b, "Terminal/Bell", "overload",
1207 "Control the bell overload behaviour");
1208 ctrl_checkbox(s, "Bell is temporarily disabled when over-used", 'd',
1209 HELPCTX(bell_overload),
1210 dlg_stdcheckbox_handler, I(offsetof(Config,bellovl)));
1211 ctrl_editbox(s, "Over-use means this many bells...", 'm', 20,
1212 HELPCTX(bell_overload),
1213 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_n)), I(-1));
1214 ctrl_editbox(s, "... in this many seconds", 't', 20,
1215 HELPCTX(bell_overload),
1216 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_t)),
62697e04 1217 I(-TICKSPERSEC));
fe8abbf4 1218 ctrl_text(s, "The bell is re-enabled after a few seconds of silence.",
1219 HELPCTX(bell_overload));
1220 ctrl_editbox(s, "Seconds of silence required", 's', 20,
1221 HELPCTX(bell_overload),
1222 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_s)),
62697e04 1223 I(-TICKSPERSEC));
fe8abbf4 1224
1225 /*
1226 * The Terminal/Features panel.
1227 */
1228 ctrl_settitle(b, "Terminal/Features",
1229 "Enabling and disabling advanced terminal features");
1230
1231 s = ctrl_getset(b, "Terminal/Features", "main", NULL);
1232 ctrl_checkbox(s, "Disable application cursor keys mode", 'u',
1233 HELPCTX(features_application),
1234 dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_c)));
1235 ctrl_checkbox(s, "Disable application keypad mode", 'k',
1236 HELPCTX(features_application),
1237 dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_k)));
1238 ctrl_checkbox(s, "Disable xterm-style mouse reporting", 'x',
1239 HELPCTX(features_mouse),
1240 dlg_stdcheckbox_handler, I(offsetof(Config,no_mouse_rep)));
1241 ctrl_checkbox(s, "Disable remote-controlled terminal resizing", 's',
1242 HELPCTX(features_resize),
1243 dlg_stdcheckbox_handler,
1244 I(offsetof(Config,no_remote_resize)));
1245 ctrl_checkbox(s, "Disable switching to alternate terminal screen", 'w',
1246 HELPCTX(features_altscreen),
1247 dlg_stdcheckbox_handler, I(offsetof(Config,no_alt_screen)));
1248 ctrl_checkbox(s, "Disable remote-controlled window title changing", 't',
1249 HELPCTX(features_retitle),
1250 dlg_stdcheckbox_handler,
1251 I(offsetof(Config,no_remote_wintitle)));
7fcdebd3 1252 ctrl_checkbox(s, "Disable remote window title querying (SECURITY)",
1253 'q', HELPCTX(features_qtitle), dlg_stdcheckbox_handler,
1254 I(offsetof(Config,no_remote_qtitle)));
fe8abbf4 1255 ctrl_checkbox(s, "Disable destructive backspace on server sending ^?",'b',
1256 HELPCTX(features_dbackspace),
1257 dlg_stdcheckbox_handler, I(offsetof(Config,no_dbackspace)));
1258 ctrl_checkbox(s, "Disable remote-controlled character set configuration",
1259 'r', HELPCTX(features_charset), dlg_stdcheckbox_handler,
1260 I(offsetof(Config,no_remote_charset)));
f0fccd51 1261 ctrl_checkbox(s, "Disable Arabic text shaping",
f4ec0818 1262 'l', HELPCTX(features_arabicshaping), dlg_stdcheckbox_handler,
f0fccd51 1263 I(offsetof(Config, arabicshaping)));
1264 ctrl_checkbox(s, "Disable bidirectional text display",
f4ec0818 1265 'd', HELPCTX(features_bidi), dlg_stdcheckbox_handler,
f0fccd51 1266 I(offsetof(Config, bidi)));
fe8abbf4 1267
1268 /*
1269 * The Window panel.
1270 */
f6f450e2 1271 str = dupprintf("Options controlling %s's window", appname);
1272 ctrl_settitle(b, "Window", str);
1273 sfree(str);
fe8abbf4 1274
1275 s = ctrl_getset(b, "Window", "size", "Set the size of the window");
1276 ctrl_columns(s, 2, 50, 50);
1277 c = ctrl_editbox(s, "Rows", 'r', 100,
1278 HELPCTX(window_size),
1279 dlg_stdeditbox_handler, I(offsetof(Config,height)),I(-1));
1280 c->generic.column = 0;
1281 c = ctrl_editbox(s, "Columns", 'm', 100,
1282 HELPCTX(window_size),
1283 dlg_stdeditbox_handler, I(offsetof(Config,width)), I(-1));
1284 c->generic.column = 1;
1285 ctrl_columns(s, 1, 100);
1286
1287 s = ctrl_getset(b, "Window", "scrollback",
1288 "Control the scrollback in the window");
1289 ctrl_editbox(s, "Lines of scrollback", 's', 50,
1290 HELPCTX(window_scrollback),
1291 dlg_stdeditbox_handler, I(offsetof(Config,savelines)), I(-1));
1292 ctrl_checkbox(s, "Display scrollbar", 'd',
1293 HELPCTX(window_scrollback),
1294 dlg_stdcheckbox_handler, I(offsetof(Config,scrollbar)));
fe8abbf4 1295 ctrl_checkbox(s, "Reset scrollback on keypress", 'k',
1296 HELPCTX(window_scrollback),
1297 dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_key)));
1298 ctrl_checkbox(s, "Reset scrollback on display activity", 'p',
1299 HELPCTX(window_scrollback),
1300 dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_disp)));
876e5d5e 1301 ctrl_checkbox(s, "Push erased text into scrollback", 'e',
1302 HELPCTX(window_erased),
1303 dlg_stdcheckbox_handler,
1304 I(offsetof(Config,erase_to_scrollback)));
fe8abbf4 1305
1306 /*
1307 * The Window/Appearance panel.
1308 */
f6f450e2 1309 str = dupprintf("Configure the appearance of %s's window", appname);
1310 ctrl_settitle(b, "Window/Appearance", str);
1311 sfree(str);
fe8abbf4 1312
1313 s = ctrl_getset(b, "Window/Appearance", "cursor",
1314 "Adjust the use of the cursor");
1315 ctrl_radiobuttons(s, "Cursor appearance:", NO_SHORTCUT, 3,
1316 HELPCTX(appearance_cursor),
1317 dlg_stdradiobutton_handler,
1318 I(offsetof(Config, cursor_type)),
1319 "Block", 'l', I(0),
1320 "Underline", 'u', I(1),
1321 "Vertical line", 'v', I(2), NULL);
1322 ctrl_checkbox(s, "Cursor blinks", 'b',
1323 HELPCTX(appearance_cursor),
1324 dlg_stdcheckbox_handler, I(offsetof(Config,blink_cur)));
1325
1326 s = ctrl_getset(b, "Window/Appearance", "font",
1327 "Font settings");
1328 ctrl_fontsel(s, "Font used in the terminal window", 'n',
1329 HELPCTX(appearance_font),
1330 dlg_stdfontsel_handler, I(offsetof(Config, font)));
1331
1332 s = ctrl_getset(b, "Window/Appearance", "mouse",
1333 "Adjust the use of the mouse pointer");
1334 ctrl_checkbox(s, "Hide mouse pointer when typing in window", 'p',
1335 HELPCTX(appearance_hidemouse),
1336 dlg_stdcheckbox_handler, I(offsetof(Config,hide_mouseptr)));
1337
1338 s = ctrl_getset(b, "Window/Appearance", "border",
1339 "Adjust the window border");
b908db15 1340 ctrl_editbox(s, "Gap between text and window edge:", 'e', 20,
fe8abbf4 1341 HELPCTX(appearance_border),
1342 dlg_stdeditbox_handler,
1343 I(offsetof(Config,window_border)), I(-1));
1344
1345 /*
1346 * The Window/Behaviour panel.
1347 */
f6f450e2 1348 str = dupprintf("Configure the behaviour of %s's window", appname);
1349 ctrl_settitle(b, "Window/Behaviour", str);
1350 sfree(str);
fe8abbf4 1351
1352 s = ctrl_getset(b, "Window/Behaviour", "title",
1353 "Adjust the behaviour of the window title");
1354 ctrl_editbox(s, "Window title:", 't', 100,
1355 HELPCTX(appearance_title),
1356 dlg_stdeditbox_handler, I(offsetof(Config,wintitle)),
1357 I(sizeof(((Config *)0)->wintitle)));
1358 ctrl_checkbox(s, "Separate window and icon titles", 'i',
1359 HELPCTX(appearance_title),
1360 dlg_stdcheckbox_handler,
1361 I(CHECKBOX_INVERT | offsetof(Config,win_name_always)));
1362
1363 s = ctrl_getset(b, "Window/Behaviour", "main", NULL);
1364 ctrl_checkbox(s, "Warn before closing window", 'w',
1365 HELPCTX(behaviour_closewarn),
1366 dlg_stdcheckbox_handler, I(offsetof(Config,warn_on_close)));
1367
1368 /*
1369 * The Window/Translation panel.
1370 */
1371 ctrl_settitle(b, "Window/Translation",
1372 "Options controlling character set translation");
1373
1374 s = ctrl_getset(b, "Window/Translation", "trans",
1375 "Character set translation on received data");
1376 ctrl_combobox(s, "Received data assumed to be in which character set:",
1377 'r', 100, HELPCTX(translation_codepage),
1378 codepage_handler, P(NULL), P(NULL));
1379
74790953 1380 s = ctrl_getset(b, "Window/Translation", "tweaks", NULL);
1381 ctrl_checkbox(s, "Treat CJK ambiguous characters as wide", 'w',
1382 HELPCTX(translation_cjk_ambig_wide),
1383 dlg_stdcheckbox_handler, I(offsetof(Config,cjk_ambig_wide)));
1384
00381fc7 1385 str = dupprintf("Adjust how %s handles line drawing characters", appname);
f6f450e2 1386 s = ctrl_getset(b, "Window/Translation", "linedraw", str);
1387 sfree(str);
fe8abbf4 1388 ctrl_radiobuttons(s, "Handling of line drawing characters:", NO_SHORTCUT,1,
1389 HELPCTX(translation_linedraw),
1390 dlg_stdradiobutton_handler,
1391 I(offsetof(Config, vtmode)),
3900c2d6 1392 "Use Unicode line drawing code points",'u',I(VT_UNICODE),
fe8abbf4 1393 "Poor man's line drawing (+, - and |)",'p',I(VT_POORMAN),
3900c2d6 1394 NULL);
00381fc7 1395 ctrl_checkbox(s, "Copy and paste line drawing characters as lqqqk",'d',
1396 HELPCTX(selection_linedraw),
1397 dlg_stdcheckbox_handler, I(offsetof(Config,rawcnp)));
fe8abbf4 1398
1399 /*
1400 * The Window/Selection panel.
1401 */
1402 ctrl_settitle(b, "Window/Selection", "Options controlling copy and paste");
fe8abbf4 1403
1404 s = ctrl_getset(b, "Window/Selection", "mouse",
1405 "Control use of mouse");
1406 ctrl_checkbox(s, "Shift overrides application's use of mouse", 'p',
1407 HELPCTX(selection_shiftdrag),
1408 dlg_stdcheckbox_handler, I(offsetof(Config,mouse_override)));
1409 ctrl_radiobuttons(s,
1410 "Default selection mode (Alt+drag does the other one):",
1411 NO_SHORTCUT, 2,
1412 HELPCTX(selection_rect),
1413 dlg_stdradiobutton_handler,
1414 I(offsetof(Config, rect_select)),
1415 "Normal", 'n', I(0),
1416 "Rectangular block", 'r', I(1), NULL);
1417
1418 s = ctrl_getset(b, "Window/Selection", "charclass",
1419 "Control the select-one-word-at-a-time mode");
1420 ccd = (struct charclass_data *)
1421 ctrl_alloc(b, sizeof(struct charclass_data));
1422 ccd->listbox = ctrl_listbox(s, "Character classes:", 'e',
1423 HELPCTX(selection_charclasses),
1424 charclass_handler, P(ccd));
1425 ccd->listbox->listbox.multisel = 1;
1426 ccd->listbox->listbox.ncols = 4;
3d88e64d 1427 ccd->listbox->listbox.percentages = snewn(4, int);
fe8abbf4 1428 ccd->listbox->listbox.percentages[0] = 15;
1429 ccd->listbox->listbox.percentages[1] = 25;
1430 ccd->listbox->listbox.percentages[2] = 20;
1431 ccd->listbox->listbox.percentages[3] = 40;
1432 ctrl_columns(s, 2, 67, 33);
1433 ccd->editbox = ctrl_editbox(s, "Set to class", 't', 50,
1434 HELPCTX(selection_charclasses),
1435 charclass_handler, P(ccd), P(NULL));
1436 ccd->editbox->generic.column = 0;
1437 ccd->button = ctrl_pushbutton(s, "Set", 's',
1438 HELPCTX(selection_charclasses),
1439 charclass_handler, P(ccd));
1440 ccd->button->generic.column = 1;
1441 ctrl_columns(s, 1, 100);
1442
1443 /*
1444 * The Window/Colours panel.
1445 */
1446 ctrl_settitle(b, "Window/Colours", "Options controlling use of colours");
1447
1448 s = ctrl_getset(b, "Window/Colours", "general",
1449 "General options for colour usage");
c6f1b8ed 1450 ctrl_checkbox(s, "Allow terminal to specify ANSI colours", 'i',
1451 HELPCTX(colours_ansi),
1452 dlg_stdcheckbox_handler, I(offsetof(Config,ansi_colour)));
cecb13f6 1453 ctrl_checkbox(s, "Allow terminal to use xterm 256-colour mode", '2',
1454 HELPCTX(colours_xterm256), dlg_stdcheckbox_handler,
1455 I(offsetof(Config,xterm_256_colour)));
fe8abbf4 1456 ctrl_checkbox(s, "Bolded text is a different colour", 'b',
1457 HELPCTX(colours_bold),
1458 dlg_stdcheckbox_handler, I(offsetof(Config,bold_colour)));
1459
f6f450e2 1460 str = dupprintf("Adjust the precise colours %s displays", appname);
1461 s = ctrl_getset(b, "Window/Colours", "adjust", str);
1462 sfree(str);
fe8abbf4 1463 ctrl_text(s, "Select a colour from the list, and then click the"
1464 " Modify button to change its appearance.",
1465 HELPCTX(colours_config));
1466 ctrl_columns(s, 2, 67, 33);
1467 cd = (struct colour_data *)ctrl_alloc(b, sizeof(struct colour_data));
1468 cd->listbox = ctrl_listbox(s, "Select a colour to adjust:", 'u',
1469 HELPCTX(colours_config), colour_handler, P(cd));
1470 cd->listbox->generic.column = 0;
18c2f87c 1471 cd->listbox->listbox.height = 7;
fe8abbf4 1472 c = ctrl_text(s, "RGB value:", HELPCTX(colours_config));
1473 c->generic.column = 1;
18c2f87c 1474 cd->redit = ctrl_editbox(s, "Red", 'r', 50, HELPCTX(colours_config),
1475 colour_handler, P(cd), P(NULL));
1476 cd->redit->generic.column = 1;
1477 cd->gedit = ctrl_editbox(s, "Green", 'n', 50, HELPCTX(colours_config),
1478 colour_handler, P(cd), P(NULL));
1479 cd->gedit->generic.column = 1;
1480 cd->bedit = ctrl_editbox(s, "Blue", 'e', 50, HELPCTX(colours_config),
1481 colour_handler, P(cd), P(NULL));
1482 cd->bedit->generic.column = 1;
fe8abbf4 1483 cd->button = ctrl_pushbutton(s, "Modify", 'm', HELPCTX(colours_config),
1484 colour_handler, P(cd));
1485 cd->button->generic.column = 1;
1486 ctrl_columns(s, 1, 100);
1487
1488 /*
3e547dd8 1489 * The Connection panel. This doesn't show up if we're in a
1490 * non-network utility such as pterm. We tell this by being
1491 * passed a protocol < 0.
fe8abbf4 1492 */
3e547dd8 1493 if (protocol >= 0) {
1494 ctrl_settitle(b, "Connection", "Options controlling the connection");
1495
05581745 1496 s = ctrl_getset(b, "Connection", "keepalive",
1497 "Sending of null packets to keep session active");
1498 ctrl_editbox(s, "Seconds between keepalives (0 to turn off)", 'k', 20,
1499 HELPCTX(connection_keepalive),
1500 dlg_stdeditbox_handler, I(offsetof(Config,ping_interval)),
1501 I(-1));
1502
3e547dd8 1503 if (!midsession) {
05581745 1504 s = ctrl_getset(b, "Connection", "tcp",
1505 "Low-level TCP connection options");
1506 ctrl_checkbox(s, "Disable Nagle's algorithm (TCP_NODELAY option)",
1507 'n', HELPCTX(connection_nodelay),
1508 dlg_stdcheckbox_handler,
1509 I(offsetof(Config,tcp_nodelay)));
1510 ctrl_checkbox(s, "Enable TCP keepalives (SO_KEEPALIVE option)",
1511 'p', HELPCTX(connection_tcpkeepalive),
1512 dlg_stdcheckbox_handler,
1513 I(offsetof(Config,tcp_keepalives)));
22db244f 1514#ifndef NO_IPV6
05581745 1515 s = ctrl_getset(b, "Connection", "ipversion",
1516 "Internet protocol version");
22db244f 1517 ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
05581745 1518 HELPCTX(connection_ipversion),
1519 dlg_stdradiobutton_handler,
1520 I(offsetof(Config, addressfamily)),
b908db15 1521 "Auto", 'u', I(ADDRTYPE_UNSPEC),
1522 "IPv4", '4', I(ADDRTYPE_IPV4),
1523 "IPv6", '6', I(ADDRTYPE_IPV6),
05581745 1524 NULL);
22db244f 1525#endif
05581745 1526 }
1527
1528 /*
1529 * A sub-panel Connection/Data, containing options that
1530 * decide on data to send to the server.
1531 */
1532 if (!midsession) {
1533 ctrl_settitle(b, "Connection/Data", "Data to send to the server");
1534
1535 s = ctrl_getset(b, "Connection/Data", "login",
1536 "Login details");
1537 ctrl_editbox(s, "Auto-login username", 'u', 50,
1538 HELPCTX(connection_username),
1539 dlg_stdeditbox_handler, I(offsetof(Config,username)),
1540 I(sizeof(((Config *)0)->username)));
1541
1542 s = ctrl_getset(b, "Connection/Data", "term",
1543 "Terminal details");
3e547dd8 1544 ctrl_editbox(s, "Terminal-type string", 't', 50,
1545 HELPCTX(connection_termtype),
1546 dlg_stdeditbox_handler, I(offsetof(Config,termtype)),
1547 I(sizeof(((Config *)0)->termtype)));
a5dd8467 1548 ctrl_editbox(s, "Terminal speeds", 's', 50,
1549 HELPCTX(connection_termspeed),
1550 dlg_stdeditbox_handler, I(offsetof(Config,termspeed)),
1551 I(sizeof(((Config *)0)->termspeed)));
73feed4f 1552
05581745 1553 s = ctrl_getset(b, "Connection/Data", "env",
1554 "Environment variables");
73feed4f 1555 ctrl_columns(s, 2, 80, 20);
1556 ed = (struct environ_data *)
1557 ctrl_alloc(b, sizeof(struct environ_data));
1558 ed->varbox = ctrl_editbox(s, "Variable", 'v', 60,
1559 HELPCTX(telnet_environ),
1560 environ_handler, P(ed), P(NULL));
1561 ed->varbox->generic.column = 0;
1562 ed->valbox = ctrl_editbox(s, "Value", 'l', 60,
1563 HELPCTX(telnet_environ),
1564 environ_handler, P(ed), P(NULL));
1565 ed->valbox->generic.column = 0;
1566 ed->addbutton = ctrl_pushbutton(s, "Add", 'd',
1567 HELPCTX(telnet_environ),
1568 environ_handler, P(ed));
1569 ed->addbutton->generic.column = 1;
1570 ed->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1571 HELPCTX(telnet_environ),
1572 environ_handler, P(ed));
1573 ed->rembutton->generic.column = 1;
1574 ctrl_columns(s, 1, 100);
1575 ed->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1576 HELPCTX(telnet_environ),
1577 environ_handler, P(ed));
1578 ed->listbox->listbox.height = 3;
1579 ed->listbox->listbox.ncols = 2;
1580 ed->listbox->listbox.percentages = snewn(2, int);
1581 ed->listbox->listbox.percentages[0] = 30;
1582 ed->listbox->listbox.percentages[1] = 70;
3e547dd8 1583 }
fe8abbf4 1584
fe8abbf4 1585 }
1586
1587 if (!midsession) {
1588 /*
1589 * The Connection/Proxy panel.
1590 */
1591 ctrl_settitle(b, "Connection/Proxy",
1592 "Options controlling proxy usage");
1593
10068a0b 1594 s = ctrl_getset(b, "Connection/Proxy", "basics", NULL);
1595 ctrl_radiobuttons(s, "Proxy type:", 't', 3,
fe8abbf4 1596 HELPCTX(proxy_type),
1597 dlg_stdradiobutton_handler,
1598 I(offsetof(Config, proxy_type)),
0f0a2507 1599 "None", I(PROXY_NONE),
10068a0b 1600 "SOCKS 4", I(PROXY_SOCKS4),
1601 "SOCKS 5", I(PROXY_SOCKS5),
0f0a2507 1602 "HTTP", I(PROXY_HTTP),
0f0a2507 1603 "Telnet", I(PROXY_TELNET),
fe8abbf4 1604 NULL);
1605 ctrl_columns(s, 2, 80, 20);
1606 c = ctrl_editbox(s, "Proxy hostname", 'y', 100,
1607 HELPCTX(proxy_main),
1608 dlg_stdeditbox_handler,
1609 I(offsetof(Config,proxy_host)),
1610 I(sizeof(((Config *)0)->proxy_host)));
1611 c->generic.column = 0;
1612 c = ctrl_editbox(s, "Port", 'p', 100,
1613 HELPCTX(proxy_main),
1614 dlg_stdeditbox_handler,
1615 I(offsetof(Config,proxy_port)),
1616 I(-1));
1617 c->generic.column = 1;
1618 ctrl_columns(s, 1, 100);
1619 ctrl_editbox(s, "Exclude Hosts/IPs", 'e', 100,
1620 HELPCTX(proxy_exclude),
1621 dlg_stdeditbox_handler,
1622 I(offsetof(Config,proxy_exclude_list)),
1623 I(sizeof(((Config *)0)->proxy_exclude_list)));
1624 ctrl_checkbox(s, "Consider proxying local host connections", 'x',
1625 HELPCTX(proxy_exclude),
1626 dlg_stdcheckbox_handler,
1627 I(offsetof(Config,even_proxy_localhost)));
1628 ctrl_radiobuttons(s, "Do DNS name lookup at proxy end:", 'd', 3,
1629 HELPCTX(proxy_dns),
1630 dlg_stdradiobutton_handler,
1631 I(offsetof(Config, proxy_dns)),
1632 "No", I(FORCE_OFF),
1633 "Auto", I(AUTO),
1634 "Yes", I(FORCE_ON), NULL);
1635 ctrl_editbox(s, "Username", 'u', 60,
1636 HELPCTX(proxy_auth),
1637 dlg_stdeditbox_handler,
1638 I(offsetof(Config,proxy_username)),
1639 I(sizeof(((Config *)0)->proxy_username)));
1640 c = ctrl_editbox(s, "Password", 'w', 60,
1641 HELPCTX(proxy_auth),
1642 dlg_stdeditbox_handler,
1643 I(offsetof(Config,proxy_password)),
1644 I(sizeof(((Config *)0)->proxy_password)));
1645 c->editbox.password = 1;
fe8abbf4 1646 ctrl_editbox(s, "Telnet command", 'm', 100,
1647 HELPCTX(proxy_command),
1648 dlg_stdeditbox_handler,
1649 I(offsetof(Config,proxy_telnet_command)),
1650 I(sizeof(((Config *)0)->proxy_telnet_command)));
fe8abbf4 1651 }
1652
1653 /*
1654 * The Telnet panel exists in the base config box, and in a
1655 * mid-session reconfig box _if_ we're using Telnet.
1656 */
1657 if (!midsession || protocol == PROT_TELNET) {
1658 /*
1659 * The Connection/Telnet panel.
1660 */
1661 ctrl_settitle(b, "Connection/Telnet",
1662 "Options controlling Telnet connections");
1663
fe8abbf4 1664 s = ctrl_getset(b, "Connection/Telnet", "protocol",
1665 "Telnet protocol adjustments");
1666
1667 if (!midsession) {
1668 ctrl_radiobuttons(s, "Handling of OLD_ENVIRON ambiguity:",
1669 NO_SHORTCUT, 2,
1670 HELPCTX(telnet_oldenviron),
1671 dlg_stdradiobutton_handler,
1672 I(offsetof(Config, rfc_environ)),
1673 "BSD (commonplace)", 'b', I(0),
1674 "RFC 1408 (unusual)", 'f', I(1), NULL);
1675 ctrl_radiobuttons(s, "Telnet negotiation mode:", 't', 2,
1676 HELPCTX(telnet_passive),
1677 dlg_stdradiobutton_handler,
1678 I(offsetof(Config, passive_telnet)),
1679 "Passive", I(1), "Active", I(0), NULL);
1680 }
76d3d354 1681 ctrl_checkbox(s, "Keyboard sends Telnet special commands", 'k',
fe8abbf4 1682 HELPCTX(telnet_specialkeys),
1683 dlg_stdcheckbox_handler,
1684 I(offsetof(Config,telnet_keyboard)));
76d3d354 1685 ctrl_checkbox(s, "Return key sends Telnet New Line instead of ^M",
1686 'm', HELPCTX(telnet_newline),
fe8abbf4 1687 dlg_stdcheckbox_handler,
1688 I(offsetof(Config,telnet_newline)));
1689 }
1690
1691 if (!midsession) {
1692
1693 /*
1694 * The Connection/Rlogin panel.
1695 */
1696 ctrl_settitle(b, "Connection/Rlogin",
1697 "Options controlling Rlogin connections");
1698
1699 s = ctrl_getset(b, "Connection/Rlogin", "data",
1700 "Data to send to the server");
fe8abbf4 1701 ctrl_editbox(s, "Local username:", 'l', 50,
1702 HELPCTX(rlogin_localuser),
1703 dlg_stdeditbox_handler, I(offsetof(Config,localusername)),
1704 I(sizeof(((Config *)0)->localusername)));
1705
1706 }
1707
1708 /*
fda2feb1 1709 * All the SSH stuff is omitted in PuTTYtel, or in a reconfig
1710 * when we're not doing SSH.
fe8abbf4 1711 */
1712
fda2feb1 1713 if (backends[3].name != NULL && (!midsession || protocol == PROT_SSH)) {
fe8abbf4 1714
1715 /*
1716 * The Connection/SSH panel.
1717 */
1718 ctrl_settitle(b, "Connection/SSH",
1719 "Options controlling SSH connections");
1720
e13bba36 1721 if (midsession && protcfginfo == 1) {
fda2feb1 1722 s = ctrl_getset(b, "Connection/SSH", "disclaimer", NULL);
1723 ctrl_text(s, "Nothing on this panel may be reconfigured in mid-"
1724 "session; it is only here so that sub-panels of it can "
1725 "exist without looking strange.", HELPCTX(no_help));
1726 }
1727
1728 if (!midsession) {
1729
1730 s = ctrl_getset(b, "Connection/SSH", "data",
1731 "Data to send to the server");
1732 ctrl_editbox(s, "Remote command:", 'r', 100,
1733 HELPCTX(ssh_command),
1734 dlg_stdeditbox_handler, I(offsetof(Config,remote_cmd)),
1735 I(sizeof(((Config *)0)->remote_cmd)));
1736
1737 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
fda2feb1 1738 ctrl_checkbox(s, "Don't start a shell or command at all", 'n',
1739 HELPCTX(ssh_noshell),
1740 dlg_stdcheckbox_handler,
1741 I(offsetof(Config,ssh_no_shell)));
e13bba36 1742 }
1743
1744 if (!midsession || protcfginfo != 1) {
1745 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1746
fda2feb1 1747 ctrl_checkbox(s, "Enable compression", 'e',
1748 HELPCTX(ssh_compress),
1749 dlg_stdcheckbox_handler,
1750 I(offsetof(Config,compression)));
e13bba36 1751 }
1752
1753 if (!midsession) {
1754 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1755
fda2feb1 1756 ctrl_radiobuttons(s, "Preferred SSH protocol version:", NO_SHORTCUT, 4,
1757 HELPCTX(ssh_protocol),
1758 dlg_stdradiobutton_handler,
1759 I(offsetof(Config, sshprot)),
1760 "1 only", 'l', I(0),
1761 "1", '1', I(1),
1762 "2", '2', I(2),
1763 "2 only", 'y', I(3), NULL);
e13bba36 1764 }
fda2feb1 1765
e13bba36 1766 if (!midsession || protcfginfo != 1) {
fda2feb1 1767 s = ctrl_getset(b, "Connection/SSH", "encryption", "Encryption options");
1768 c = ctrl_draglist(s, "Encryption cipher selection policy:", 's',
1769 HELPCTX(ssh_ciphers),
1770 cipherlist_handler, P(NULL));
1771 c->listbox.height = 6;
1772
2e85c969 1773 ctrl_checkbox(s, "Enable legacy use of single-DES in SSH-2", 'i',
bb524800 1774 HELPCTX(ssh_ciphers),
fda2feb1 1775 dlg_stdcheckbox_handler,
1776 I(offsetof(Config,ssh2_des_cbc)));
e6c1536e 1777 }
fe8abbf4 1778
e6c1536e 1779 /*
1780 * The Connection/SSH/Kex panel. (Owing to repeat key
f89c3294 1781 * exchange, this is all meaningful in mid-session _if_
2e85c969 1782 * we're using SSH-2 or haven't decided yet.)
e6c1536e 1783 */
f89c3294 1784 if (protcfginfo != 1) {
1785 ctrl_settitle(b, "Connection/SSH/Kex",
1786 "Options controlling SSH key exchange");
1787
1788 s = ctrl_getset(b, "Connection/SSH/Kex", "main",
1789 "Key exchange algorithm options");
2e077f2e 1790 c = ctrl_draglist(s, "Algorithm selection policy:", 's',
f89c3294 1791 HELPCTX(ssh_kexlist),
1792 kexlist_handler, P(NULL));
1793 c->listbox.height = 5;
1794
1795 s = ctrl_getset(b, "Connection/SSH/Kex", "repeat",
1796 "Options controlling key re-exchange");
1797
1798 ctrl_editbox(s, "Max minutes before rekey (0 for no limit)", 't', 20,
1799 HELPCTX(ssh_kex_repeat),
1800 dlg_stdeditbox_handler,
1801 I(offsetof(Config,ssh_rekey_time)),
1802 I(-1));
1803 ctrl_editbox(s, "Max data before rekey (0 for no limit)", 'x', 20,
1804 HELPCTX(ssh_kex_repeat),
1805 dlg_stdeditbox_handler,
1806 I(offsetof(Config,ssh_rekey_data)),
1807 I(16));
1808 ctrl_text(s, "(Use 1M for 1 megabyte, 1G for 1 gigabyte etc)",
1809 HELPCTX(ssh_kex_repeat));
1810 }
e6c1536e 1811
1812 if (!midsession) {
83e7d008 1813
fda2feb1 1814 /*
1815 * The Connection/SSH/Auth panel.
1816 */
1817 ctrl_settitle(b, "Connection/SSH/Auth",
1818 "Options controlling SSH authentication");
fe8abbf4 1819
a1a1fae4 1820 s = ctrl_getset(b, "Connection/SSH/Auth", "main", NULL);
1821 ctrl_checkbox(s, "Bypass authentication entirely (SSH-2 only)", 'b',
1822 HELPCTX(ssh_auth_bypass),
1823 dlg_stdcheckbox_handler,
1824 I(offsetof(Config,ssh_no_userauth)));
1825
fda2feb1 1826 s = ctrl_getset(b, "Connection/SSH/Auth", "methods",
1827 "Authentication methods");
2e85c969 1828 ctrl_checkbox(s, "Attempt TIS or CryptoCard auth (SSH-1)", 'm',
fda2feb1 1829 HELPCTX(ssh_auth_tis),
1830 dlg_stdcheckbox_handler,
1831 I(offsetof(Config,try_tis_auth)));
2e85c969 1832 ctrl_checkbox(s, "Attempt \"keyboard-interactive\" auth (SSH-2)",
fda2feb1 1833 'i', HELPCTX(ssh_auth_ki),
1834 dlg_stdcheckbox_handler,
1835 I(offsetof(Config,try_ki_auth)));
1836
1837 s = ctrl_getset(b, "Connection/SSH/Auth", "params",
1838 "Authentication parameters");
1839 ctrl_checkbox(s, "Allow agent forwarding", 'f',
1840 HELPCTX(ssh_auth_agentfwd),
1841 dlg_stdcheckbox_handler, I(offsetof(Config,agentfwd)));
2e85c969 1842 ctrl_checkbox(s, "Allow attempted changes of username in SSH-2", 'u',
fda2feb1 1843 HELPCTX(ssh_auth_changeuser),
1844 dlg_stdcheckbox_handler,
1845 I(offsetof(Config,change_username)));
1846 ctrl_filesel(s, "Private key file for authentication:", 'k',
1847 FILTER_KEY_FILES, FALSE, "Select private key file",
1848 HELPCTX(ssh_auth_privkey),
1849 dlg_stdfilesel_handler, I(offsetof(Config, keyfile)));
1850 }
fe8abbf4 1851
fda2feb1 1852 if (!midsession) {
05581745 1853 /*
c6ccd5c2 1854 * The Connection/SSH/TTY panel.
1855 */
1856 ctrl_settitle(b, "Connection/SSH/TTY", "Remote terminal settings");
1857
1858 s = ctrl_getset(b, "Connection/SSH/TTY", "sshtty", NULL);
1859 ctrl_checkbox(s, "Don't allocate a pseudo-terminal", 'p',
1860 HELPCTX(ssh_nopty),
1861 dlg_stdcheckbox_handler,
1862 I(offsetof(Config,nopty)));
1863
1864 s = ctrl_getset(b, "Connection/SSH/TTY", "ttymodes",
1865 "Terminal modes");
1866 td = (struct ttymodes_data *)
1867 ctrl_alloc(b, sizeof(struct ttymodes_data));
1868 ctrl_columns(s, 2, 75, 25);
1869 c = ctrl_text(s, "Terminal modes to send:", HELPCTX(ssh_ttymodes));
1870 c->generic.column = 0;
1871 td->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1872 HELPCTX(ssh_ttymodes),
1873 ttymodes_handler, P(td));
1874 td->rembutton->generic.column = 1;
1875 td->rembutton->generic.tabdelay = 1;
1876 ctrl_columns(s, 1, 100);
1877 td->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1878 HELPCTX(ssh_ttymodes),
1879 ttymodes_handler, P(td));
1880 td->listbox->listbox.multisel = 1;
1881 td->listbox->listbox.height = 4;
1882 td->listbox->listbox.ncols = 2;
1883 td->listbox->listbox.percentages = snewn(2, int);
1884 td->listbox->listbox.percentages[0] = 40;
1885 td->listbox->listbox.percentages[1] = 60;
1886 ctrl_tabdelay(s, td->rembutton);
1887 ctrl_columns(s, 2, 75, 25);
1888 td->modelist = ctrl_droplist(s, "Mode:", 'm', 67,
1889 HELPCTX(ssh_ttymodes),
1890 ttymodes_handler, P(td));
1891 td->modelist->generic.column = 0;
1892 td->addbutton = ctrl_pushbutton(s, "Add", 'd',
1893 HELPCTX(ssh_ttymodes),
1894 ttymodes_handler, P(td));
1895 td->addbutton->generic.column = 1;
1896 td->addbutton->generic.tabdelay = 1;
1897 ctrl_columns(s, 1, 100); /* column break */
1898 /* Bit of a hack to get the value radio buttons and
1899 * edit-box on the same row. */
1900 ctrl_columns(s, 3, 25, 50, 25);
1901 c = ctrl_text(s, "Value:", HELPCTX(ssh_ttymodes));
1902 c->generic.column = 0;
1903 td->valradio = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 2,
1904 HELPCTX(ssh_ttymodes),
1905 ttymodes_handler, P(td),
1906 "Auto", NO_SHORTCUT, P(NULL),
1907 "This:", NO_SHORTCUT, P(NULL),
1908 NULL);
1909 td->valradio->generic.column = 1;
1910 td->valbox = ctrl_editbox(s, NULL, NO_SHORTCUT, 100,
1911 HELPCTX(ssh_ttymodes),
1912 ttymodes_handler, P(td), P(NULL));
1913 td->valbox->generic.column = 2;
1914 ctrl_tabdelay(s, td->addbutton);
1915
1916 }
1917
1918 if (!midsession) {
1919 /*
05581745 1920 * The Connection/SSH/X11 panel.
1921 */
1922 ctrl_settitle(b, "Connection/SSH/X11",
1923 "Options controlling SSH X11 forwarding");
1924
1925 s = ctrl_getset(b, "Connection/SSH/X11", "x11", "X11 forwarding");
fda2feb1 1926 ctrl_checkbox(s, "Enable X11 forwarding", 'e',
1927 HELPCTX(ssh_tunnels_x11),
1928 dlg_stdcheckbox_handler,I(offsetof(Config,x11_forward)));
1929 ctrl_editbox(s, "X display location", 'x', 50,
1930 HELPCTX(ssh_tunnels_x11),
1931 dlg_stdeditbox_handler, I(offsetof(Config,x11_display)),
1932 I(sizeof(((Config *)0)->x11_display)));
1933 ctrl_radiobuttons(s, "Remote X11 authentication protocol", 'u', 2,
1934 HELPCTX(ssh_tunnels_x11auth),
1935 dlg_stdradiobutton_handler,
1936 I(offsetof(Config, x11_auth)),
1937 "MIT-Magic-Cookie-1", I(X11_MIT),
1938 "XDM-Authorization-1", I(X11_XDM), NULL);
1939 }
fe8abbf4 1940
05581745 1941 /*
1942 * The Tunnels panel _is_ still available in mid-session.
1943 */
1944 ctrl_settitle(b, "Connection/SSH/Tunnels",
1945 "Options controlling SSH port forwarding");
1946
fe8abbf4 1947 s = ctrl_getset(b, "Connection/SSH/Tunnels", "portfwd",
1948 "Port forwarding");
1949 ctrl_checkbox(s, "Local ports accept connections from other hosts",'t',
1950 HELPCTX(ssh_tunnels_portfwd_localhost),
1951 dlg_stdcheckbox_handler,
1952 I(offsetof(Config,lport_acceptall)));
2e85c969 1953 ctrl_checkbox(s, "Remote ports do the same (SSH-2 only)", 'p',
fe8abbf4 1954 HELPCTX(ssh_tunnels_portfwd_localhost),
1955 dlg_stdcheckbox_handler,
1956 I(offsetof(Config,rport_acceptall)));
1957
1958 ctrl_columns(s, 3, 55, 20, 25);
1959 c = ctrl_text(s, "Forwarded ports:", HELPCTX(ssh_tunnels_portfwd));
1960 c->generic.column = COLUMN_FIELD(0,2);
1961 /* You want to select from the list, _then_ hit Remove. So tab order
1962 * should be that way round. */
1963 pfd = (struct portfwd_data *)ctrl_alloc(b,sizeof(struct portfwd_data));
1964 pfd->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1965 HELPCTX(ssh_tunnels_portfwd),
1966 portfwd_handler, P(pfd));
1967 pfd->rembutton->generic.column = 2;
1968 pfd->rembutton->generic.tabdelay = 1;
1969 pfd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1970 HELPCTX(ssh_tunnels_portfwd),
1971 portfwd_handler, P(pfd));
1972 pfd->listbox->listbox.height = 3;
37dbf11c 1973 pfd->listbox->listbox.ncols = 2;
3d88e64d 1974 pfd->listbox->listbox.percentages = snewn(2, int);
37dbf11c 1975 pfd->listbox->listbox.percentages[0] = 20;
1976 pfd->listbox->listbox.percentages[1] = 80;
fe8abbf4 1977 ctrl_tabdelay(s, pfd->rembutton);
1978 ctrl_text(s, "Add new forwarded port:", HELPCTX(ssh_tunnels_portfwd));
1979 /* You want to enter source, destination and type, _then_ hit Add.
1980 * Again, we adjust the tab order to reflect this. */
1981 pfd->addbutton = ctrl_pushbutton(s, "Add", 'd',
1982 HELPCTX(ssh_tunnels_portfwd),
1983 portfwd_handler, P(pfd));
1984 pfd->addbutton->generic.column = 2;
1985 pfd->addbutton->generic.tabdelay = 1;
1986 pfd->sourcebox = ctrl_editbox(s, "Source port", 's', 40,
1987 HELPCTX(ssh_tunnels_portfwd),
1988 portfwd_handler, P(pfd), P(NULL));
1989 pfd->sourcebox->generic.column = 0;
1990 pfd->destbox = ctrl_editbox(s, "Destination", 'i', 67,
1991 HELPCTX(ssh_tunnels_portfwd),
1992 portfwd_handler, P(pfd), P(NULL));
820ebe3b 1993 pfd->direction = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
fe8abbf4 1994 HELPCTX(ssh_tunnels_portfwd),
1995 portfwd_handler, P(pfd),
1996 "Local", 'l', P(NULL),
820ebe3b 1997 "Remote", 'm', P(NULL),
1998 "Dynamic", 'y', P(NULL),
1999 NULL);
05581745 2000#ifndef NO_IPV6
22db244f 2001 pfd->addressfamily =
2002 ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
05581745 2003 HELPCTX(ssh_tunnels_portfwd_ipversion),
2004 portfwd_handler, P(pfd),
b908db15 2005 "Auto", 'u', I(ADDRTYPE_UNSPEC),
2006 "IPv4", '4', I(ADDRTYPE_IPV4),
2007 "IPv6", '6', I(ADDRTYPE_IPV6),
05581745 2008 NULL);
22db244f 2009#endif
fe8abbf4 2010 ctrl_tabdelay(s, pfd->addbutton);
2011 ctrl_columns(s, 1, 100);
2012
fda2feb1 2013 if (!midsession) {
2014 /*
2015 * The Connection/SSH/Bugs panel.
2016 */
2017 ctrl_settitle(b, "Connection/SSH/Bugs",
2018 "Workarounds for SSH server bugs");
2019
2020 s = ctrl_getset(b, "Connection/SSH/Bugs", "main",
2021 "Detection of known bugs in SSH servers");
2e85c969 2022 ctrl_droplist(s, "Chokes on SSH-1 ignore messages", 'i', 20,
fda2feb1 2023 HELPCTX(ssh_bugs_ignore1),
2024 sshbug_handler, I(offsetof(Config,sshbug_ignore1)));
2e85c969 2025 ctrl_droplist(s, "Refuses all SSH-1 password camouflage", 's', 20,
fda2feb1 2026 HELPCTX(ssh_bugs_plainpw1),
2027 sshbug_handler, I(offsetof(Config,sshbug_plainpw1)));
2e85c969 2028 ctrl_droplist(s, "Chokes on SSH-1 RSA authentication", 'r', 20,
fda2feb1 2029 HELPCTX(ssh_bugs_rsa1),
2030 sshbug_handler, I(offsetof(Config,sshbug_rsa1)));
2e85c969 2031 ctrl_droplist(s, "Miscomputes SSH-2 HMAC keys", 'm', 20,
fda2feb1 2032 HELPCTX(ssh_bugs_hmac2),
2033 sshbug_handler, I(offsetof(Config,sshbug_hmac2)));
2e85c969 2034 ctrl_droplist(s, "Miscomputes SSH-2 encryption keys", 'e', 20,
fda2feb1 2035 HELPCTX(ssh_bugs_derivekey2),
2036 sshbug_handler, I(offsetof(Config,sshbug_derivekey2)));
2e85c969 2037 ctrl_droplist(s, "Requires padding on SSH-2 RSA signatures", 'p', 20,
fda2feb1 2038 HELPCTX(ssh_bugs_rsapad2),
2039 sshbug_handler, I(offsetof(Config,sshbug_rsapad2)));
19f47a7d 2040 ctrl_droplist(s, "Misuses the session ID in SSH-2 PK auth", 'n', 20,
fda2feb1 2041 HELPCTX(ssh_bugs_pksessid2),
2042 sshbug_handler, I(offsetof(Config,sshbug_pksessid2)));
19f47a7d 2043 ctrl_droplist(s, "Handles SSH-2 key re-exchange badly", 'k', 20,
f382c87d 2044 HELPCTX(ssh_bugs_rekey2),
2045 sshbug_handler, I(offsetof(Config,sshbug_rekey2)));
fda2feb1 2046 }
fe8abbf4 2047 }
2048}