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