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