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