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