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