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