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