If a new session was saved from Change Settings, a side-effect on Windows was
[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 },
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;
12745e35 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 }
12745e35 300 isdef = !strcmp(ssd->sesslist.sessions[i], "Default Settings");
301 load_settings(ssd->sesslist.sessions[i], !isdef, cfg);
fe8abbf4 302 if (!isdef) {
12745e35 303 strncpy(savedsession, ssd->sesslist.sessions[i],
4e6d4091 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);
12745e35 347 for (i = 0; i < ssd->sesslist.nsessions; i++)
348 dlg_listbox_add(ctrl, dlg, ssd->sesslist.sessions[i]);
fe8abbf4 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 }
12745e35 379 isdef = !strcmp(ssd->sesslist.sessions[i], "Default Settings");
fe8abbf4 380 if (!isdef) {
12745e35 381 strncpy(savedsession, ssd->sesslist.sessions[i],
4e6d4091 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 }
12745e35 395 get_sesslist(&ssd->sesslist, FALSE);
396 get_sesslist(&ssd->sesslist, TRUE);
fe8abbf4 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 {
12745e35 405 del_settings(ssd->sesslist.sessions[i]);
406 get_sesslist(&ssd->sesslist, FALSE);
407 get_sesslist(&ssd->sesslist, TRUE);
fe8abbf4 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
12745e35 822void setup_config_box(struct controlbox *b, int midsession,
823 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);
12745e35 907 get_sesslist(&ssd->sesslist, TRUE);
48c4dd7c 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
74790953 1285 s = ctrl_getset(b, "Window/Translation", "tweaks", NULL);
1286 ctrl_checkbox(s, "Treat CJK ambiguous characters as wide", 'w',
1287 HELPCTX(translation_cjk_ambig_wide),
1288 dlg_stdcheckbox_handler, I(offsetof(Config,cjk_ambig_wide)));
1289
00381fc7 1290 str = dupprintf("Adjust how %s handles line drawing characters", appname);
f6f450e2 1291 s = ctrl_getset(b, "Window/Translation", "linedraw", str);
1292 sfree(str);
fe8abbf4 1293 ctrl_radiobuttons(s, "Handling of line drawing characters:", NO_SHORTCUT,1,
1294 HELPCTX(translation_linedraw),
1295 dlg_stdradiobutton_handler,
1296 I(offsetof(Config, vtmode)),
3900c2d6 1297 "Use Unicode line drawing code points",'u',I(VT_UNICODE),
fe8abbf4 1298 "Poor man's line drawing (+, - and |)",'p',I(VT_POORMAN),
3900c2d6 1299 NULL);
00381fc7 1300 ctrl_checkbox(s, "Copy and paste line drawing characters as lqqqk",'d',
1301 HELPCTX(selection_linedraw),
1302 dlg_stdcheckbox_handler, I(offsetof(Config,rawcnp)));
fe8abbf4 1303
1304 /*
1305 * The Window/Selection panel.
1306 */
1307 ctrl_settitle(b, "Window/Selection", "Options controlling copy and paste");
fe8abbf4 1308
1309 s = ctrl_getset(b, "Window/Selection", "mouse",
1310 "Control use of mouse");
1311 ctrl_checkbox(s, "Shift overrides application's use of mouse", 'p',
1312 HELPCTX(selection_shiftdrag),
1313 dlg_stdcheckbox_handler, I(offsetof(Config,mouse_override)));
1314 ctrl_radiobuttons(s,
1315 "Default selection mode (Alt+drag does the other one):",
1316 NO_SHORTCUT, 2,
1317 HELPCTX(selection_rect),
1318 dlg_stdradiobutton_handler,
1319 I(offsetof(Config, rect_select)),
1320 "Normal", 'n', I(0),
1321 "Rectangular block", 'r', I(1), NULL);
1322
1323 s = ctrl_getset(b, "Window/Selection", "charclass",
1324 "Control the select-one-word-at-a-time mode");
1325 ccd = (struct charclass_data *)
1326 ctrl_alloc(b, sizeof(struct charclass_data));
1327 ccd->listbox = ctrl_listbox(s, "Character classes:", 'e',
1328 HELPCTX(selection_charclasses),
1329 charclass_handler, P(ccd));
1330 ccd->listbox->listbox.multisel = 1;
1331 ccd->listbox->listbox.ncols = 4;
3d88e64d 1332 ccd->listbox->listbox.percentages = snewn(4, int);
fe8abbf4 1333 ccd->listbox->listbox.percentages[0] = 15;
1334 ccd->listbox->listbox.percentages[1] = 25;
1335 ccd->listbox->listbox.percentages[2] = 20;
1336 ccd->listbox->listbox.percentages[3] = 40;
1337 ctrl_columns(s, 2, 67, 33);
1338 ccd->editbox = ctrl_editbox(s, "Set to class", 't', 50,
1339 HELPCTX(selection_charclasses),
1340 charclass_handler, P(ccd), P(NULL));
1341 ccd->editbox->generic.column = 0;
1342 ccd->button = ctrl_pushbutton(s, "Set", 's',
1343 HELPCTX(selection_charclasses),
1344 charclass_handler, P(ccd));
1345 ccd->button->generic.column = 1;
1346 ctrl_columns(s, 1, 100);
1347
1348 /*
1349 * The Window/Colours panel.
1350 */
1351 ctrl_settitle(b, "Window/Colours", "Options controlling use of colours");
1352
1353 s = ctrl_getset(b, "Window/Colours", "general",
1354 "General options for colour usage");
c6f1b8ed 1355 ctrl_checkbox(s, "Allow terminal to specify ANSI colours", 'i',
1356 HELPCTX(colours_ansi),
1357 dlg_stdcheckbox_handler, I(offsetof(Config,ansi_colour)));
cecb13f6 1358 ctrl_checkbox(s, "Allow terminal to use xterm 256-colour mode", '2',
1359 HELPCTX(colours_xterm256), dlg_stdcheckbox_handler,
1360 I(offsetof(Config,xterm_256_colour)));
fe8abbf4 1361 ctrl_checkbox(s, "Bolded text is a different colour", 'b',
1362 HELPCTX(colours_bold),
1363 dlg_stdcheckbox_handler, I(offsetof(Config,bold_colour)));
1364
f6f450e2 1365 str = dupprintf("Adjust the precise colours %s displays", appname);
1366 s = ctrl_getset(b, "Window/Colours", "adjust", str);
1367 sfree(str);
fe8abbf4 1368 ctrl_text(s, "Select a colour from the list, and then click the"
1369 " Modify button to change its appearance.",
1370 HELPCTX(colours_config));
1371 ctrl_columns(s, 2, 67, 33);
1372 cd = (struct colour_data *)ctrl_alloc(b, sizeof(struct colour_data));
1373 cd->listbox = ctrl_listbox(s, "Select a colour to adjust:", 'u',
1374 HELPCTX(colours_config), colour_handler, P(cd));
1375 cd->listbox->generic.column = 0;
18c2f87c 1376 cd->listbox->listbox.height = 7;
fe8abbf4 1377 c = ctrl_text(s, "RGB value:", HELPCTX(colours_config));
1378 c->generic.column = 1;
18c2f87c 1379 cd->redit = ctrl_editbox(s, "Red", 'r', 50, HELPCTX(colours_config),
1380 colour_handler, P(cd), P(NULL));
1381 cd->redit->generic.column = 1;
1382 cd->gedit = ctrl_editbox(s, "Green", 'n', 50, HELPCTX(colours_config),
1383 colour_handler, P(cd), P(NULL));
1384 cd->gedit->generic.column = 1;
1385 cd->bedit = ctrl_editbox(s, "Blue", 'e', 50, HELPCTX(colours_config),
1386 colour_handler, P(cd), P(NULL));
1387 cd->bedit->generic.column = 1;
fe8abbf4 1388 cd->button = ctrl_pushbutton(s, "Modify", 'm', HELPCTX(colours_config),
1389 colour_handler, P(cd));
1390 cd->button->generic.column = 1;
1391 ctrl_columns(s, 1, 100);
1392
1393 /*
3e547dd8 1394 * The Connection panel. This doesn't show up if we're in a
1395 * non-network utility such as pterm. We tell this by being
1396 * passed a protocol < 0.
fe8abbf4 1397 */
3e547dd8 1398 if (protocol >= 0) {
1399 ctrl_settitle(b, "Connection", "Options controlling the connection");
1400
05581745 1401 s = ctrl_getset(b, "Connection", "keepalive",
1402 "Sending of null packets to keep session active");
1403 ctrl_editbox(s, "Seconds between keepalives (0 to turn off)", 'k', 20,
1404 HELPCTX(connection_keepalive),
1405 dlg_stdeditbox_handler, I(offsetof(Config,ping_interval)),
1406 I(-1));
1407
3e547dd8 1408 if (!midsession) {
05581745 1409 s = ctrl_getset(b, "Connection", "tcp",
1410 "Low-level TCP connection options");
1411 ctrl_checkbox(s, "Disable Nagle's algorithm (TCP_NODELAY option)",
1412 'n', HELPCTX(connection_nodelay),
1413 dlg_stdcheckbox_handler,
1414 I(offsetof(Config,tcp_nodelay)));
1415 ctrl_checkbox(s, "Enable TCP keepalives (SO_KEEPALIVE option)",
1416 'p', HELPCTX(connection_tcpkeepalive),
1417 dlg_stdcheckbox_handler,
1418 I(offsetof(Config,tcp_keepalives)));
22db244f 1419#ifndef NO_IPV6
05581745 1420 s = ctrl_getset(b, "Connection", "ipversion",
1421 "Internet protocol version");
22db244f 1422 ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
05581745 1423 HELPCTX(connection_ipversion),
1424 dlg_stdradiobutton_handler,
1425 I(offsetof(Config, addressfamily)),
1426 "Auto", NO_SHORTCUT, I(ADDRTYPE_UNSPEC),
1427 "IPv4", NO_SHORTCUT, I(ADDRTYPE_IPV4),
05581745 1428 "IPv6", NO_SHORTCUT, I(ADDRTYPE_IPV6),
05581745 1429 NULL);
22db244f 1430#endif
05581745 1431 }
1432
1433 /*
1434 * A sub-panel Connection/Data, containing options that
1435 * decide on data to send to the server.
1436 */
1437 if (!midsession) {
1438 ctrl_settitle(b, "Connection/Data", "Data to send to the server");
1439
1440 s = ctrl_getset(b, "Connection/Data", "login",
1441 "Login details");
1442 ctrl_editbox(s, "Auto-login username", 'u', 50,
1443 HELPCTX(connection_username),
1444 dlg_stdeditbox_handler, I(offsetof(Config,username)),
1445 I(sizeof(((Config *)0)->username)));
1446
1447 s = ctrl_getset(b, "Connection/Data", "term",
1448 "Terminal details");
3e547dd8 1449 ctrl_editbox(s, "Terminal-type string", 't', 50,
1450 HELPCTX(connection_termtype),
1451 dlg_stdeditbox_handler, I(offsetof(Config,termtype)),
1452 I(sizeof(((Config *)0)->termtype)));
a5dd8467 1453 ctrl_editbox(s, "Terminal speeds", 's', 50,
1454 HELPCTX(connection_termspeed),
1455 dlg_stdeditbox_handler, I(offsetof(Config,termspeed)),
1456 I(sizeof(((Config *)0)->termspeed)));
73feed4f 1457
05581745 1458 s = ctrl_getset(b, "Connection/Data", "env",
1459 "Environment variables");
73feed4f 1460 ctrl_columns(s, 2, 80, 20);
1461 ed = (struct environ_data *)
1462 ctrl_alloc(b, sizeof(struct environ_data));
1463 ed->varbox = ctrl_editbox(s, "Variable", 'v', 60,
1464 HELPCTX(telnet_environ),
1465 environ_handler, P(ed), P(NULL));
1466 ed->varbox->generic.column = 0;
1467 ed->valbox = ctrl_editbox(s, "Value", 'l', 60,
1468 HELPCTX(telnet_environ),
1469 environ_handler, P(ed), P(NULL));
1470 ed->valbox->generic.column = 0;
1471 ed->addbutton = ctrl_pushbutton(s, "Add", 'd',
1472 HELPCTX(telnet_environ),
1473 environ_handler, P(ed));
1474 ed->addbutton->generic.column = 1;
1475 ed->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1476 HELPCTX(telnet_environ),
1477 environ_handler, P(ed));
1478 ed->rembutton->generic.column = 1;
1479 ctrl_columns(s, 1, 100);
1480 ed->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1481 HELPCTX(telnet_environ),
1482 environ_handler, P(ed));
1483 ed->listbox->listbox.height = 3;
1484 ed->listbox->listbox.ncols = 2;
1485 ed->listbox->listbox.percentages = snewn(2, int);
1486 ed->listbox->listbox.percentages[0] = 30;
1487 ed->listbox->listbox.percentages[1] = 70;
3e547dd8 1488 }
fe8abbf4 1489
fe8abbf4 1490 }
1491
1492 if (!midsession) {
1493 /*
1494 * The Connection/Proxy panel.
1495 */
1496 ctrl_settitle(b, "Connection/Proxy",
1497 "Options controlling proxy usage");
1498
10068a0b 1499 s = ctrl_getset(b, "Connection/Proxy", "basics", NULL);
1500 ctrl_radiobuttons(s, "Proxy type:", 't', 3,
fe8abbf4 1501 HELPCTX(proxy_type),
1502 dlg_stdradiobutton_handler,
1503 I(offsetof(Config, proxy_type)),
0f0a2507 1504 "None", I(PROXY_NONE),
10068a0b 1505 "SOCKS 4", I(PROXY_SOCKS4),
1506 "SOCKS 5", I(PROXY_SOCKS5),
0f0a2507 1507 "HTTP", I(PROXY_HTTP),
0f0a2507 1508 "Telnet", I(PROXY_TELNET),
fe8abbf4 1509 NULL);
1510 ctrl_columns(s, 2, 80, 20);
1511 c = ctrl_editbox(s, "Proxy hostname", 'y', 100,
1512 HELPCTX(proxy_main),
1513 dlg_stdeditbox_handler,
1514 I(offsetof(Config,proxy_host)),
1515 I(sizeof(((Config *)0)->proxy_host)));
1516 c->generic.column = 0;
1517 c = ctrl_editbox(s, "Port", 'p', 100,
1518 HELPCTX(proxy_main),
1519 dlg_stdeditbox_handler,
1520 I(offsetof(Config,proxy_port)),
1521 I(-1));
1522 c->generic.column = 1;
1523 ctrl_columns(s, 1, 100);
1524 ctrl_editbox(s, "Exclude Hosts/IPs", 'e', 100,
1525 HELPCTX(proxy_exclude),
1526 dlg_stdeditbox_handler,
1527 I(offsetof(Config,proxy_exclude_list)),
1528 I(sizeof(((Config *)0)->proxy_exclude_list)));
1529 ctrl_checkbox(s, "Consider proxying local host connections", 'x',
1530 HELPCTX(proxy_exclude),
1531 dlg_stdcheckbox_handler,
1532 I(offsetof(Config,even_proxy_localhost)));
1533 ctrl_radiobuttons(s, "Do DNS name lookup at proxy end:", 'd', 3,
1534 HELPCTX(proxy_dns),
1535 dlg_stdradiobutton_handler,
1536 I(offsetof(Config, proxy_dns)),
1537 "No", I(FORCE_OFF),
1538 "Auto", I(AUTO),
1539 "Yes", I(FORCE_ON), NULL);
1540 ctrl_editbox(s, "Username", 'u', 60,
1541 HELPCTX(proxy_auth),
1542 dlg_stdeditbox_handler,
1543 I(offsetof(Config,proxy_username)),
1544 I(sizeof(((Config *)0)->proxy_username)));
1545 c = ctrl_editbox(s, "Password", 'w', 60,
1546 HELPCTX(proxy_auth),
1547 dlg_stdeditbox_handler,
1548 I(offsetof(Config,proxy_password)),
1549 I(sizeof(((Config *)0)->proxy_password)));
1550 c->editbox.password = 1;
fe8abbf4 1551 ctrl_editbox(s, "Telnet command", 'm', 100,
1552 HELPCTX(proxy_command),
1553 dlg_stdeditbox_handler,
1554 I(offsetof(Config,proxy_telnet_command)),
1555 I(sizeof(((Config *)0)->proxy_telnet_command)));
fe8abbf4 1556 }
1557
1558 /*
1559 * The Telnet panel exists in the base config box, and in a
1560 * mid-session reconfig box _if_ we're using Telnet.
1561 */
1562 if (!midsession || protocol == PROT_TELNET) {
1563 /*
1564 * The Connection/Telnet panel.
1565 */
1566 ctrl_settitle(b, "Connection/Telnet",
1567 "Options controlling Telnet connections");
1568
fe8abbf4 1569 s = ctrl_getset(b, "Connection/Telnet", "protocol",
1570 "Telnet protocol adjustments");
1571
1572 if (!midsession) {
1573 ctrl_radiobuttons(s, "Handling of OLD_ENVIRON ambiguity:",
1574 NO_SHORTCUT, 2,
1575 HELPCTX(telnet_oldenviron),
1576 dlg_stdradiobutton_handler,
1577 I(offsetof(Config, rfc_environ)),
1578 "BSD (commonplace)", 'b', I(0),
1579 "RFC 1408 (unusual)", 'f', I(1), NULL);
1580 ctrl_radiobuttons(s, "Telnet negotiation mode:", 't', 2,
1581 HELPCTX(telnet_passive),
1582 dlg_stdradiobutton_handler,
1583 I(offsetof(Config, passive_telnet)),
1584 "Passive", I(1), "Active", I(0), NULL);
1585 }
76d3d354 1586 ctrl_checkbox(s, "Keyboard sends Telnet special commands", 'k',
fe8abbf4 1587 HELPCTX(telnet_specialkeys),
1588 dlg_stdcheckbox_handler,
1589 I(offsetof(Config,telnet_keyboard)));
76d3d354 1590 ctrl_checkbox(s, "Return key sends Telnet New Line instead of ^M",
1591 'm', HELPCTX(telnet_newline),
fe8abbf4 1592 dlg_stdcheckbox_handler,
1593 I(offsetof(Config,telnet_newline)));
1594 }
1595
1596 if (!midsession) {
1597
1598 /*
1599 * The Connection/Rlogin panel.
1600 */
1601 ctrl_settitle(b, "Connection/Rlogin",
1602 "Options controlling Rlogin connections");
1603
1604 s = ctrl_getset(b, "Connection/Rlogin", "data",
1605 "Data to send to the server");
fe8abbf4 1606 ctrl_editbox(s, "Local username:", 'l', 50,
1607 HELPCTX(rlogin_localuser),
1608 dlg_stdeditbox_handler, I(offsetof(Config,localusername)),
1609 I(sizeof(((Config *)0)->localusername)));
1610
1611 }
1612
1613 /*
fda2feb1 1614 * All the SSH stuff is omitted in PuTTYtel, or in a reconfig
1615 * when we're not doing SSH.
fe8abbf4 1616 */
1617
fda2feb1 1618 if (backends[3].name != NULL && (!midsession || protocol == PROT_SSH)) {
fe8abbf4 1619
1620 /*
1621 * The Connection/SSH panel.
1622 */
1623 ctrl_settitle(b, "Connection/SSH",
1624 "Options controlling SSH connections");
1625
e13bba36 1626 if (midsession && protcfginfo == 1) {
fda2feb1 1627 s = ctrl_getset(b, "Connection/SSH", "disclaimer", NULL);
1628 ctrl_text(s, "Nothing on this panel may be reconfigured in mid-"
1629 "session; it is only here so that sub-panels of it can "
1630 "exist without looking strange.", HELPCTX(no_help));
1631 }
1632
1633 if (!midsession) {
1634
1635 s = ctrl_getset(b, "Connection/SSH", "data",
1636 "Data to send to the server");
1637 ctrl_editbox(s, "Remote command:", 'r', 100,
1638 HELPCTX(ssh_command),
1639 dlg_stdeditbox_handler, I(offsetof(Config,remote_cmd)),
1640 I(sizeof(((Config *)0)->remote_cmd)));
1641
1642 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1643 ctrl_checkbox(s, "Don't allocate a pseudo-terminal", 'p',
1644 HELPCTX(ssh_nopty),
1645 dlg_stdcheckbox_handler,
1646 I(offsetof(Config,nopty)));
1647 ctrl_checkbox(s, "Don't start a shell or command at all", 'n',
1648 HELPCTX(ssh_noshell),
1649 dlg_stdcheckbox_handler,
1650 I(offsetof(Config,ssh_no_shell)));
e13bba36 1651 }
1652
1653 if (!midsession || protcfginfo != 1) {
1654 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1655
fda2feb1 1656 ctrl_checkbox(s, "Enable compression", 'e',
1657 HELPCTX(ssh_compress),
1658 dlg_stdcheckbox_handler,
1659 I(offsetof(Config,compression)));
e13bba36 1660 }
1661
1662 if (!midsession) {
1663 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1664
fda2feb1 1665 ctrl_radiobuttons(s, "Preferred SSH protocol version:", NO_SHORTCUT, 4,
1666 HELPCTX(ssh_protocol),
1667 dlg_stdradiobutton_handler,
1668 I(offsetof(Config, sshprot)),
1669 "1 only", 'l', I(0),
1670 "1", '1', I(1),
1671 "2", '2', I(2),
1672 "2 only", 'y', I(3), NULL);
e13bba36 1673 }
fda2feb1 1674
e13bba36 1675 if (!midsession || protcfginfo != 1) {
fda2feb1 1676 s = ctrl_getset(b, "Connection/SSH", "encryption", "Encryption options");
1677 c = ctrl_draglist(s, "Encryption cipher selection policy:", 's',
1678 HELPCTX(ssh_ciphers),
1679 cipherlist_handler, P(NULL));
1680 c->listbox.height = 6;
1681
2e85c969 1682 ctrl_checkbox(s, "Enable legacy use of single-DES in SSH-2", 'i',
bb524800 1683 HELPCTX(ssh_ciphers),
fda2feb1 1684 dlg_stdcheckbox_handler,
1685 I(offsetof(Config,ssh2_des_cbc)));
e6c1536e 1686 }
fe8abbf4 1687
e6c1536e 1688 /*
1689 * The Connection/SSH/Kex panel. (Owing to repeat key
f89c3294 1690 * exchange, this is all meaningful in mid-session _if_
2e85c969 1691 * we're using SSH-2 or haven't decided yet.)
e6c1536e 1692 */
f89c3294 1693 if (protcfginfo != 1) {
1694 ctrl_settitle(b, "Connection/SSH/Kex",
1695 "Options controlling SSH key exchange");
1696
1697 s = ctrl_getset(b, "Connection/SSH/Kex", "main",
1698 "Key exchange algorithm options");
2e077f2e 1699 c = ctrl_draglist(s, "Algorithm selection policy:", 's',
f89c3294 1700 HELPCTX(ssh_kexlist),
1701 kexlist_handler, P(NULL));
1702 c->listbox.height = 5;
1703
1704 s = ctrl_getset(b, "Connection/SSH/Kex", "repeat",
1705 "Options controlling key re-exchange");
1706
1707 ctrl_editbox(s, "Max minutes before rekey (0 for no limit)", 't', 20,
1708 HELPCTX(ssh_kex_repeat),
1709 dlg_stdeditbox_handler,
1710 I(offsetof(Config,ssh_rekey_time)),
1711 I(-1));
1712 ctrl_editbox(s, "Max data before rekey (0 for no limit)", 'x', 20,
1713 HELPCTX(ssh_kex_repeat),
1714 dlg_stdeditbox_handler,
1715 I(offsetof(Config,ssh_rekey_data)),
1716 I(16));
1717 ctrl_text(s, "(Use 1M for 1 megabyte, 1G for 1 gigabyte etc)",
1718 HELPCTX(ssh_kex_repeat));
1719 }
e6c1536e 1720
1721 if (!midsession) {
83e7d008 1722
fda2feb1 1723 /*
1724 * The Connection/SSH/Auth panel.
1725 */
1726 ctrl_settitle(b, "Connection/SSH/Auth",
1727 "Options controlling SSH authentication");
fe8abbf4 1728
fda2feb1 1729 s = ctrl_getset(b, "Connection/SSH/Auth", "methods",
1730 "Authentication methods");
2e85c969 1731 ctrl_checkbox(s, "Attempt TIS or CryptoCard auth (SSH-1)", 'm',
fda2feb1 1732 HELPCTX(ssh_auth_tis),
1733 dlg_stdcheckbox_handler,
1734 I(offsetof(Config,try_tis_auth)));
2e85c969 1735 ctrl_checkbox(s, "Attempt \"keyboard-interactive\" auth (SSH-2)",
fda2feb1 1736 'i', HELPCTX(ssh_auth_ki),
1737 dlg_stdcheckbox_handler,
1738 I(offsetof(Config,try_ki_auth)));
1739
1740 s = ctrl_getset(b, "Connection/SSH/Auth", "params",
1741 "Authentication parameters");
1742 ctrl_checkbox(s, "Allow agent forwarding", 'f',
1743 HELPCTX(ssh_auth_agentfwd),
1744 dlg_stdcheckbox_handler, I(offsetof(Config,agentfwd)));
2e85c969 1745 ctrl_checkbox(s, "Allow attempted changes of username in SSH-2", 'u',
fda2feb1 1746 HELPCTX(ssh_auth_changeuser),
1747 dlg_stdcheckbox_handler,
1748 I(offsetof(Config,change_username)));
1749 ctrl_filesel(s, "Private key file for authentication:", 'k',
1750 FILTER_KEY_FILES, FALSE, "Select private key file",
1751 HELPCTX(ssh_auth_privkey),
1752 dlg_stdfilesel_handler, I(offsetof(Config, keyfile)));
1753 }
fe8abbf4 1754
fda2feb1 1755 if (!midsession) {
05581745 1756 /*
1757 * The Connection/SSH/X11 panel.
1758 */
1759 ctrl_settitle(b, "Connection/SSH/X11",
1760 "Options controlling SSH X11 forwarding");
1761
1762 s = ctrl_getset(b, "Connection/SSH/X11", "x11", "X11 forwarding");
fda2feb1 1763 ctrl_checkbox(s, "Enable X11 forwarding", 'e',
1764 HELPCTX(ssh_tunnels_x11),
1765 dlg_stdcheckbox_handler,I(offsetof(Config,x11_forward)));
1766 ctrl_editbox(s, "X display location", 'x', 50,
1767 HELPCTX(ssh_tunnels_x11),
1768 dlg_stdeditbox_handler, I(offsetof(Config,x11_display)),
1769 I(sizeof(((Config *)0)->x11_display)));
1770 ctrl_radiobuttons(s, "Remote X11 authentication protocol", 'u', 2,
1771 HELPCTX(ssh_tunnels_x11auth),
1772 dlg_stdradiobutton_handler,
1773 I(offsetof(Config, x11_auth)),
1774 "MIT-Magic-Cookie-1", I(X11_MIT),
1775 "XDM-Authorization-1", I(X11_XDM), NULL);
1776 }
fe8abbf4 1777
05581745 1778 /*
1779 * The Tunnels panel _is_ still available in mid-session.
1780 */
1781 ctrl_settitle(b, "Connection/SSH/Tunnels",
1782 "Options controlling SSH port forwarding");
1783
fe8abbf4 1784 s = ctrl_getset(b, "Connection/SSH/Tunnels", "portfwd",
1785 "Port forwarding");
1786 ctrl_checkbox(s, "Local ports accept connections from other hosts",'t',
1787 HELPCTX(ssh_tunnels_portfwd_localhost),
1788 dlg_stdcheckbox_handler,
1789 I(offsetof(Config,lport_acceptall)));
2e85c969 1790 ctrl_checkbox(s, "Remote ports do the same (SSH-2 only)", 'p',
fe8abbf4 1791 HELPCTX(ssh_tunnels_portfwd_localhost),
1792 dlg_stdcheckbox_handler,
1793 I(offsetof(Config,rport_acceptall)));
1794
1795 ctrl_columns(s, 3, 55, 20, 25);
1796 c = ctrl_text(s, "Forwarded ports:", HELPCTX(ssh_tunnels_portfwd));
1797 c->generic.column = COLUMN_FIELD(0,2);
1798 /* You want to select from the list, _then_ hit Remove. So tab order
1799 * should be that way round. */
1800 pfd = (struct portfwd_data *)ctrl_alloc(b,sizeof(struct portfwd_data));
1801 pfd->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1802 HELPCTX(ssh_tunnels_portfwd),
1803 portfwd_handler, P(pfd));
1804 pfd->rembutton->generic.column = 2;
1805 pfd->rembutton->generic.tabdelay = 1;
1806 pfd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1807 HELPCTX(ssh_tunnels_portfwd),
1808 portfwd_handler, P(pfd));
1809 pfd->listbox->listbox.height = 3;
37dbf11c 1810 pfd->listbox->listbox.ncols = 2;
3d88e64d 1811 pfd->listbox->listbox.percentages = snewn(2, int);
37dbf11c 1812 pfd->listbox->listbox.percentages[0] = 20;
1813 pfd->listbox->listbox.percentages[1] = 80;
fe8abbf4 1814 ctrl_tabdelay(s, pfd->rembutton);
1815 ctrl_text(s, "Add new forwarded port:", HELPCTX(ssh_tunnels_portfwd));
1816 /* You want to enter source, destination and type, _then_ hit Add.
1817 * Again, we adjust the tab order to reflect this. */
1818 pfd->addbutton = ctrl_pushbutton(s, "Add", 'd',
1819 HELPCTX(ssh_tunnels_portfwd),
1820 portfwd_handler, P(pfd));
1821 pfd->addbutton->generic.column = 2;
1822 pfd->addbutton->generic.tabdelay = 1;
1823 pfd->sourcebox = ctrl_editbox(s, "Source port", 's', 40,
1824 HELPCTX(ssh_tunnels_portfwd),
1825 portfwd_handler, P(pfd), P(NULL));
1826 pfd->sourcebox->generic.column = 0;
1827 pfd->destbox = ctrl_editbox(s, "Destination", 'i', 67,
1828 HELPCTX(ssh_tunnels_portfwd),
1829 portfwd_handler, P(pfd), P(NULL));
820ebe3b 1830 pfd->direction = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
fe8abbf4 1831 HELPCTX(ssh_tunnels_portfwd),
1832 portfwd_handler, P(pfd),
1833 "Local", 'l', P(NULL),
820ebe3b 1834 "Remote", 'm', P(NULL),
1835 "Dynamic", 'y', P(NULL),
1836 NULL);
05581745 1837#ifndef NO_IPV6
22db244f 1838 pfd->addressfamily =
1839 ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
05581745 1840 HELPCTX(ssh_tunnels_portfwd_ipversion),
1841 portfwd_handler, P(pfd),
1842 "Auto", NO_SHORTCUT, I(ADDRTYPE_UNSPEC),
1843 "IPv4", NO_SHORTCUT, I(ADDRTYPE_IPV4),
05581745 1844 "IPv6", NO_SHORTCUT, I(ADDRTYPE_IPV6),
05581745 1845 NULL);
22db244f 1846#endif
fe8abbf4 1847 ctrl_tabdelay(s, pfd->addbutton);
1848 ctrl_columns(s, 1, 100);
1849
fda2feb1 1850 if (!midsession) {
1851 /*
1852 * The Connection/SSH/Bugs panel.
1853 */
1854 ctrl_settitle(b, "Connection/SSH/Bugs",
1855 "Workarounds for SSH server bugs");
1856
1857 s = ctrl_getset(b, "Connection/SSH/Bugs", "main",
1858 "Detection of known bugs in SSH servers");
2e85c969 1859 ctrl_droplist(s, "Chokes on SSH-1 ignore messages", 'i', 20,
fda2feb1 1860 HELPCTX(ssh_bugs_ignore1),
1861 sshbug_handler, I(offsetof(Config,sshbug_ignore1)));
2e85c969 1862 ctrl_droplist(s, "Refuses all SSH-1 password camouflage", 's', 20,
fda2feb1 1863 HELPCTX(ssh_bugs_plainpw1),
1864 sshbug_handler, I(offsetof(Config,sshbug_plainpw1)));
2e85c969 1865 ctrl_droplist(s, "Chokes on SSH-1 RSA authentication", 'r', 20,
fda2feb1 1866 HELPCTX(ssh_bugs_rsa1),
1867 sshbug_handler, I(offsetof(Config,sshbug_rsa1)));
2e85c969 1868 ctrl_droplist(s, "Miscomputes SSH-2 HMAC keys", 'm', 20,
fda2feb1 1869 HELPCTX(ssh_bugs_hmac2),
1870 sshbug_handler, I(offsetof(Config,sshbug_hmac2)));
2e85c969 1871 ctrl_droplist(s, "Miscomputes SSH-2 encryption keys", 'e', 20,
fda2feb1 1872 HELPCTX(ssh_bugs_derivekey2),
1873 sshbug_handler, I(offsetof(Config,sshbug_derivekey2)));
2e85c969 1874 ctrl_droplist(s, "Requires padding on SSH-2 RSA signatures", 'p', 20,
fda2feb1 1875 HELPCTX(ssh_bugs_rsapad2),
1876 sshbug_handler, I(offsetof(Config,sshbug_rsapad2)));
19f47a7d 1877 ctrl_droplist(s, "Misuses the session ID in SSH-2 PK auth", 'n', 20,
fda2feb1 1878 HELPCTX(ssh_bugs_pksessid2),
1879 sshbug_handler, I(offsetof(Config,sshbug_pksessid2)));
19f47a7d 1880 ctrl_droplist(s, "Handles SSH-2 key re-exchange badly", 'k', 20,
f382c87d 1881 HELPCTX(ssh_bugs_rekey2),
1882 sshbug_handler, I(offsetof(Config,sshbug_rekey2)));
fda2feb1 1883 }
fe8abbf4 1884 }
1885}