Implement xterm 256-colour mode.
[u/mdw/putty] / config.c
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
15 static 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
53 static 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
84 static 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 }
113 dlg_listbox_addwithid(ctrl, dlg, cstr, c);
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
127 static 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);
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 }
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
159 static 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;
165 const char *cp;
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
182 static 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);
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);
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
207 #define SAVEDSESSION_LEN 2048
208
209 struct sessionsaver_data {
210 union control *editbox, *listbox, *loadbutton, *savebutton, *delbutton;
211 union control *okbutton, *cancelbutton;
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 */
220 static int load_selected_session(struct sessionsaver_data *ssd,
221 char *savedsession,
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) {
233 strncpy(savedsession, ssd->sesslist->sessions[i],
234 SAVEDSESSION_LEN);
235 savedsession[SAVEDSESSION_LEN-1] = '\0';
236 } else {
237 savedsession[0] = '\0';
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
246 static 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;
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).
259 *
260 * Of course, this doesn't need to be done mid-session.
261 */
262 if (!ssd->editbox) {
263 savedsession = NULL;
264 } else if (!dlg_get_privdata(ssd->editbox, dlg)) {
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 }
271
272 if (event == EVENT_REFRESH) {
273 if (ctrl == ssd->editbox) {
274 dlg_editbox_set(ctrl, dlg, savedsession);
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) {
285 dlg_editbox_get(ctrl, dlg, savedsession,
286 SAVEDSESSION_LEN);
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 */
297 if (load_selected_session(ssd, savedsession, dlg, cfg) &&
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) {
302 int isdef = !strcmp(savedsession, "Default Settings");
303 if (!savedsession[0]) {
304 int i = dlg_listbox_index(ssd->listbox, dlg);
305 if (i < 0) {
306 dlg_beep(dlg);
307 return;
308 }
309 isdef = !strcmp(ssd->sesslist->sessions[i], "Default Settings");
310 if (!isdef) {
311 strncpy(savedsession, ssd->sesslist->sessions[i],
312 SAVEDSESSION_LEN);
313 savedsession[SAVEDSESSION_LEN-1] = '\0';
314 } else {
315 savedsession[0] = '\0';
316 }
317 }
318 {
319 char *errmsg = save_settings(savedsession, !isdef, cfg);
320 if (errmsg) {
321 dlg_error_msg(dlg, errmsg);
322 sfree(errmsg);
323 }
324 }
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) {
330 int i = dlg_listbox_index(ssd->listbox, dlg);
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) {
340 if (!savedsession) {
341 /* In a mid-session Change Settings, Apply is always OK. */
342 dlg_end(dlg, 1);
343 return;
344 }
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 */
352 if (dlg_last_focused(ctrl, dlg) == ssd->listbox && !*cfg->host) {
353 Config cfg2;
354 if (!load_selected_session(ssd, savedsession, dlg, &cfg2)) {
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 cfg->remote_cmd_ptr = cfg->remote_cmd; /* nasty */
362 dlg_end(dlg, 1);
363 } else
364 dlg_beep(dlg);
365 return;
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
382 struct charclass_data {
383 union control *listbox, *editbox, *button;
384 };
385
386 static 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
421 struct colour_data {
422 union control *listbox, *redit, *gedit, *bedit, *button;
423 };
424
425 static 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
439 static 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);
455 dlg_editbox_set(cd->redit, dlg, "");
456 dlg_editbox_set(cd->gedit, dlg, "");
457 dlg_editbox_set(cd->bedit, dlg, "");
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 }
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 }
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];
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);
530 }
531 }
532
533 struct environ_data {
534 union control *varbox, *valbox, *addbutton, *rembutton, *listbox;
535 };
536
537 static 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
622 struct portfwd_data {
623 union control *addbutton, *rembutton, *listbox;
624 union control *sourcebox, *destbox, *direction;
625 };
626
627 static 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);
644 } else if (ctrl == pfd->direction) {
645 /*
646 * Default is Local.
647 */
648 dlg_radiobutton_set(ctrl, dlg, 0);
649 }
650 } else if (event == EVENT_ACTION) {
651 if (ctrl == pfd->addbutton) {
652 char str[sizeof(cfg->portfwd)];
653 char *p;
654 int whichbutton = dlg_radiobutton_get(pfd->direction, dlg);
655 if (whichbutton == 0)
656 str[0] = 'L';
657 else if (whichbutton == 1)
658 str[0] = 'R';
659 else
660 str[0] = 'D';
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);
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';
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
730 void 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;
740 char *str;
741
742 ssd = (struct sessionsaver_data *)
743 ctrl_alloc(b, sizeof(struct sessionsaver_data));
744 memset(ssd, 0, sizeof(*ssd));
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));
762 ssd->cancelbutton->button.iscancel = TRUE;
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 */
770 str = dupprintf("Basic options for your %s session", appname);
771 ctrl_settitle(b, "Session", str);
772 sfree(str);
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);
788 if (backends[3].name == NULL) {
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);
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);
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;
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;
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);
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 }
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
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
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)),
1009 I(-TICKSPERSEC));
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)),
1015 I(-TICKSPERSEC));
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)));
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)));
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)));
1053 ctrl_checkbox(s, "Disable Arabic text shaping",
1054 'l', HELPCTX(features_arabicshaping), dlg_stdcheckbox_handler,
1055 I(offsetof(Config, arabicshaping)));
1056 ctrl_checkbox(s, "Disable bidirectional text display",
1057 'd', HELPCTX(features_bidi), dlg_stdcheckbox_handler,
1058 I(offsetof(Config, bidi)));
1059
1060 /*
1061 * The Window panel.
1062 */
1063 str = dupprintf("Options controlling %s's window", appname);
1064 ctrl_settitle(b, "Window", str);
1065 sfree(str);
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)));
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)));
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)));
1097
1098 /*
1099 * The Window/Appearance panel.
1100 */
1101 str = dupprintf("Configure the appearance of %s's window", appname);
1102 ctrl_settitle(b, "Window/Appearance", str);
1103 sfree(str);
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 */
1140 str = dupprintf("Configure the behaviour of %s's window", appname);
1141 ctrl_settitle(b, "Window/Behaviour", str);
1142 sfree(str);
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
1172 str = dupprintf("Adjust how %s handles line drawing characters", appname);
1173 s = ctrl_getset(b, "Window/Translation", "linedraw", str);
1174 sfree(str);
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)),
1179 "Use Unicode line drawing code points",'u',I(VT_UNICODE),
1180 "Poor man's line drawing (+, - and |)",'p',I(VT_POORMAN),
1181 NULL);
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)));
1185
1186 /*
1187 * The Window/Selection panel.
1188 */
1189 ctrl_settitle(b, "Window/Selection", "Options controlling copy and paste");
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;
1214 ccd->listbox->listbox.percentages = snewn(4, int);
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");
1237 ctrl_checkbox(s, "Allow terminal to specify ANSI colours", 'i',
1238 HELPCTX(colours_ansi),
1239 dlg_stdcheckbox_handler, I(offsetof(Config,ansi_colour)));
1240 ctrl_checkbox(s, "Allow terminal to use xterm 256-colour mode", '2',
1241 HELPCTX(colours_xterm256), dlg_stdcheckbox_handler,
1242 I(offsetof(Config,xterm_256_colour)));
1243 ctrl_checkbox(s, "Bolded text is a different colour", 'b',
1244 HELPCTX(colours_bold),
1245 dlg_stdcheckbox_handler, I(offsetof(Config,bold_colour)));
1246
1247 str = dupprintf("Adjust the precise colours %s displays", appname);
1248 s = ctrl_getset(b, "Window/Colours", "adjust", str);
1249 sfree(str);
1250 ctrl_text(s, "Select a colour from the list, and then click the"
1251 " Modify button to change its appearance.",
1252 HELPCTX(colours_config));
1253 ctrl_columns(s, 2, 67, 33);
1254 cd = (struct colour_data *)ctrl_alloc(b, sizeof(struct colour_data));
1255 cd->listbox = ctrl_listbox(s, "Select a colour to adjust:", 'u',
1256 HELPCTX(colours_config), colour_handler, P(cd));
1257 cd->listbox->generic.column = 0;
1258 cd->listbox->listbox.height = 7;
1259 c = ctrl_text(s, "RGB value:", HELPCTX(colours_config));
1260 c->generic.column = 1;
1261 cd->redit = ctrl_editbox(s, "Red", 'r', 50, HELPCTX(colours_config),
1262 colour_handler, P(cd), P(NULL));
1263 cd->redit->generic.column = 1;
1264 cd->gedit = ctrl_editbox(s, "Green", 'n', 50, HELPCTX(colours_config),
1265 colour_handler, P(cd), P(NULL));
1266 cd->gedit->generic.column = 1;
1267 cd->bedit = ctrl_editbox(s, "Blue", 'e', 50, HELPCTX(colours_config),
1268 colour_handler, P(cd), P(NULL));
1269 cd->bedit->generic.column = 1;
1270 cd->button = ctrl_pushbutton(s, "Modify", 'm', HELPCTX(colours_config),
1271 colour_handler, P(cd));
1272 cd->button->generic.column = 1;
1273 ctrl_columns(s, 1, 100);
1274
1275 /*
1276 * The Connection panel. This doesn't show up if we're in a
1277 * non-network utility such as pterm. We tell this by being
1278 * passed a protocol < 0.
1279 */
1280 if (protocol >= 0) {
1281 ctrl_settitle(b, "Connection", "Options controlling the connection");
1282
1283 if (!midsession) {
1284 s = ctrl_getset(b, "Connection", "data",
1285 "Data to send to the server");
1286 ctrl_editbox(s, "Terminal-type string", 't', 50,
1287 HELPCTX(connection_termtype),
1288 dlg_stdeditbox_handler, I(offsetof(Config,termtype)),
1289 I(sizeof(((Config *)0)->termtype)));
1290 ctrl_editbox(s, "Terminal speeds", 's', 50,
1291 HELPCTX(connection_termspeed),
1292 dlg_stdeditbox_handler, I(offsetof(Config,termspeed)),
1293 I(sizeof(((Config *)0)->termspeed)));
1294 ctrl_editbox(s, "Auto-login username", 'u', 50,
1295 HELPCTX(connection_username),
1296 dlg_stdeditbox_handler, I(offsetof(Config,username)),
1297 I(sizeof(((Config *)0)->username)));
1298
1299 ctrl_text(s, "Environment variables:", HELPCTX(telnet_environ));
1300 ctrl_columns(s, 2, 80, 20);
1301 ed = (struct environ_data *)
1302 ctrl_alloc(b, sizeof(struct environ_data));
1303 ed->varbox = ctrl_editbox(s, "Variable", 'v', 60,
1304 HELPCTX(telnet_environ),
1305 environ_handler, P(ed), P(NULL));
1306 ed->varbox->generic.column = 0;
1307 ed->valbox = ctrl_editbox(s, "Value", 'l', 60,
1308 HELPCTX(telnet_environ),
1309 environ_handler, P(ed), P(NULL));
1310 ed->valbox->generic.column = 0;
1311 ed->addbutton = ctrl_pushbutton(s, "Add", 'd',
1312 HELPCTX(telnet_environ),
1313 environ_handler, P(ed));
1314 ed->addbutton->generic.column = 1;
1315 ed->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1316 HELPCTX(telnet_environ),
1317 environ_handler, P(ed));
1318 ed->rembutton->generic.column = 1;
1319 ctrl_columns(s, 1, 100);
1320 ed->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1321 HELPCTX(telnet_environ),
1322 environ_handler, P(ed));
1323 ed->listbox->listbox.height = 3;
1324 ed->listbox->listbox.ncols = 2;
1325 ed->listbox->listbox.percentages = snewn(2, int);
1326 ed->listbox->listbox.percentages[0] = 30;
1327 ed->listbox->listbox.percentages[1] = 70;
1328 }
1329
1330 s = ctrl_getset(b, "Connection", "keepalive",
1331 "Sending of null packets to keep session active");
1332 ctrl_editbox(s, "Seconds between keepalives (0 to turn off)", 'k', 20,
1333 HELPCTX(connection_keepalive),
1334 dlg_stdeditbox_handler, I(offsetof(Config,ping_interval)),
1335 I(-1));
1336
1337 if (!midsession) {
1338 s = ctrl_getset(b, "Connection", "tcp",
1339 "Low-level TCP connection options");
1340 ctrl_checkbox(s, "Disable Nagle's algorithm (TCP_NODELAY option)",
1341 'n', HELPCTX(connection_nodelay),
1342 dlg_stdcheckbox_handler,
1343 I(offsetof(Config,tcp_nodelay)));
1344 ctrl_checkbox(s, "Enable TCP keepalives (SO_KEEPALIVE option)",
1345 'p', HELPCTX(connection_tcpkeepalive),
1346 dlg_stdcheckbox_handler,
1347 I(offsetof(Config,tcp_keepalives)));
1348 }
1349
1350 }
1351
1352 if (!midsession) {
1353 /*
1354 * The Connection/Proxy panel.
1355 */
1356 ctrl_settitle(b, "Connection/Proxy",
1357 "Options controlling proxy usage");
1358
1359 s = ctrl_getset(b, "Connection/Proxy", "basics", NULL);
1360 ctrl_radiobuttons(s, "Proxy type:", 't', 3,
1361 HELPCTX(proxy_type),
1362 dlg_stdradiobutton_handler,
1363 I(offsetof(Config, proxy_type)),
1364 "None", I(PROXY_NONE),
1365 "SOCKS 4", I(PROXY_SOCKS4),
1366 "SOCKS 5", I(PROXY_SOCKS5),
1367 "HTTP", I(PROXY_HTTP),
1368 "Telnet", I(PROXY_TELNET),
1369 NULL);
1370 ctrl_columns(s, 2, 80, 20);
1371 c = ctrl_editbox(s, "Proxy hostname", 'y', 100,
1372 HELPCTX(proxy_main),
1373 dlg_stdeditbox_handler,
1374 I(offsetof(Config,proxy_host)),
1375 I(sizeof(((Config *)0)->proxy_host)));
1376 c->generic.column = 0;
1377 c = ctrl_editbox(s, "Port", 'p', 100,
1378 HELPCTX(proxy_main),
1379 dlg_stdeditbox_handler,
1380 I(offsetof(Config,proxy_port)),
1381 I(-1));
1382 c->generic.column = 1;
1383 ctrl_columns(s, 1, 100);
1384 ctrl_editbox(s, "Exclude Hosts/IPs", 'e', 100,
1385 HELPCTX(proxy_exclude),
1386 dlg_stdeditbox_handler,
1387 I(offsetof(Config,proxy_exclude_list)),
1388 I(sizeof(((Config *)0)->proxy_exclude_list)));
1389 ctrl_checkbox(s, "Consider proxying local host connections", 'x',
1390 HELPCTX(proxy_exclude),
1391 dlg_stdcheckbox_handler,
1392 I(offsetof(Config,even_proxy_localhost)));
1393 ctrl_radiobuttons(s, "Do DNS name lookup at proxy end:", 'd', 3,
1394 HELPCTX(proxy_dns),
1395 dlg_stdradiobutton_handler,
1396 I(offsetof(Config, proxy_dns)),
1397 "No", I(FORCE_OFF),
1398 "Auto", I(AUTO),
1399 "Yes", I(FORCE_ON), NULL);
1400 ctrl_editbox(s, "Username", 'u', 60,
1401 HELPCTX(proxy_auth),
1402 dlg_stdeditbox_handler,
1403 I(offsetof(Config,proxy_username)),
1404 I(sizeof(((Config *)0)->proxy_username)));
1405 c = ctrl_editbox(s, "Password", 'w', 60,
1406 HELPCTX(proxy_auth),
1407 dlg_stdeditbox_handler,
1408 I(offsetof(Config,proxy_password)),
1409 I(sizeof(((Config *)0)->proxy_password)));
1410 c->editbox.password = 1;
1411 ctrl_editbox(s, "Telnet command", 'm', 100,
1412 HELPCTX(proxy_command),
1413 dlg_stdeditbox_handler,
1414 I(offsetof(Config,proxy_telnet_command)),
1415 I(sizeof(((Config *)0)->proxy_telnet_command)));
1416 }
1417
1418 /*
1419 * The Telnet panel exists in the base config box, and in a
1420 * mid-session reconfig box _if_ we're using Telnet.
1421 */
1422 if (!midsession || protocol == PROT_TELNET) {
1423 /*
1424 * The Connection/Telnet panel.
1425 */
1426 ctrl_settitle(b, "Connection/Telnet",
1427 "Options controlling Telnet connections");
1428
1429 s = ctrl_getset(b, "Connection/Telnet", "protocol",
1430 "Telnet protocol adjustments");
1431
1432 if (!midsession) {
1433 ctrl_radiobuttons(s, "Handling of OLD_ENVIRON ambiguity:",
1434 NO_SHORTCUT, 2,
1435 HELPCTX(telnet_oldenviron),
1436 dlg_stdradiobutton_handler,
1437 I(offsetof(Config, rfc_environ)),
1438 "BSD (commonplace)", 'b', I(0),
1439 "RFC 1408 (unusual)", 'f', I(1), NULL);
1440 ctrl_radiobuttons(s, "Telnet negotiation mode:", 't', 2,
1441 HELPCTX(telnet_passive),
1442 dlg_stdradiobutton_handler,
1443 I(offsetof(Config, passive_telnet)),
1444 "Passive", I(1), "Active", I(0), NULL);
1445 }
1446 ctrl_checkbox(s, "Keyboard sends Telnet special commands", 'k',
1447 HELPCTX(telnet_specialkeys),
1448 dlg_stdcheckbox_handler,
1449 I(offsetof(Config,telnet_keyboard)));
1450 ctrl_checkbox(s, "Return key sends Telnet New Line instead of ^M",
1451 'm', HELPCTX(telnet_newline),
1452 dlg_stdcheckbox_handler,
1453 I(offsetof(Config,telnet_newline)));
1454 }
1455
1456 if (!midsession) {
1457
1458 /*
1459 * The Connection/Rlogin panel.
1460 */
1461 ctrl_settitle(b, "Connection/Rlogin",
1462 "Options controlling Rlogin connections");
1463
1464 s = ctrl_getset(b, "Connection/Rlogin", "data",
1465 "Data to send to the server");
1466 ctrl_editbox(s, "Local username:", 'l', 50,
1467 HELPCTX(rlogin_localuser),
1468 dlg_stdeditbox_handler, I(offsetof(Config,localusername)),
1469 I(sizeof(((Config *)0)->localusername)));
1470
1471 }
1472
1473 /*
1474 * All the SSH stuff is omitted in PuTTYtel.
1475 */
1476
1477 if (!midsession && backends[3].name != NULL) {
1478
1479 /*
1480 * The Connection/SSH panel.
1481 */
1482 ctrl_settitle(b, "Connection/SSH",
1483 "Options controlling SSH connections");
1484
1485 s = ctrl_getset(b, "Connection/SSH", "data",
1486 "Data to send to the server");
1487 ctrl_editbox(s, "Remote command:", 'r', 100,
1488 HELPCTX(ssh_command),
1489 dlg_stdeditbox_handler, I(offsetof(Config,remote_cmd)),
1490 I(sizeof(((Config *)0)->remote_cmd)));
1491
1492 s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1493 ctrl_checkbox(s, "Don't allocate a pseudo-terminal", 'p',
1494 HELPCTX(ssh_nopty),
1495 dlg_stdcheckbox_handler,
1496 I(offsetof(Config,nopty)));
1497 ctrl_checkbox(s, "Don't start a shell or command at all", 'n',
1498 HELPCTX(ssh_noshell),
1499 dlg_stdcheckbox_handler,
1500 I(offsetof(Config,ssh_no_shell)));
1501 ctrl_checkbox(s, "Enable compression", 'e',
1502 HELPCTX(ssh_compress),
1503 dlg_stdcheckbox_handler,
1504 I(offsetof(Config,compression)));
1505 ctrl_radiobuttons(s, "Preferred SSH protocol version:", NO_SHORTCUT, 4,
1506 HELPCTX(ssh_protocol),
1507 dlg_stdradiobutton_handler,
1508 I(offsetof(Config, sshprot)),
1509 "1 only", 'l', I(0),
1510 "1", '1', I(1),
1511 "2", '2', I(2),
1512 "2 only", 'y', I(3), NULL);
1513
1514 s = ctrl_getset(b, "Connection/SSH", "encryption", "Encryption options");
1515 c = ctrl_draglist(s, "Encryption cipher selection policy:", 's',
1516 HELPCTX(ssh_ciphers),
1517 cipherlist_handler, P(NULL));
1518 c->listbox.height = 6;
1519
1520 ctrl_checkbox(s, "Enable legacy use of single-DES in SSH 2", 'i',
1521 HELPCTX(ssh_ciphers),
1522 dlg_stdcheckbox_handler,
1523 I(offsetof(Config,ssh2_des_cbc)));
1524
1525 /*
1526 * The Connection/SSH/Auth panel.
1527 */
1528 ctrl_settitle(b, "Connection/SSH/Auth",
1529 "Options controlling SSH authentication");
1530
1531 s = ctrl_getset(b, "Connection/SSH/Auth", "methods",
1532 "Authentication methods");
1533 ctrl_checkbox(s, "Attempt TIS or CryptoCard auth (SSH1)", 'm',
1534 HELPCTX(ssh_auth_tis),
1535 dlg_stdcheckbox_handler,
1536 I(offsetof(Config,try_tis_auth)));
1537 ctrl_checkbox(s, "Attempt \"keyboard-interactive\" auth (SSH2)",
1538 'i', HELPCTX(ssh_auth_ki),
1539 dlg_stdcheckbox_handler,
1540 I(offsetof(Config,try_ki_auth)));
1541
1542 s = ctrl_getset(b, "Connection/SSH/Auth", "params",
1543 "Authentication parameters");
1544 ctrl_checkbox(s, "Allow agent forwarding", 'f',
1545 HELPCTX(ssh_auth_agentfwd),
1546 dlg_stdcheckbox_handler, I(offsetof(Config,agentfwd)));
1547 ctrl_checkbox(s, "Allow attempted changes of username in SSH2", 'u',
1548 HELPCTX(ssh_auth_changeuser),
1549 dlg_stdcheckbox_handler,
1550 I(offsetof(Config,change_username)));
1551 ctrl_filesel(s, "Private key file for authentication:", 'k',
1552 FILTER_KEY_FILES, FALSE, "Select private key file",
1553 HELPCTX(ssh_auth_privkey),
1554 dlg_stdfilesel_handler, I(offsetof(Config, keyfile)));
1555
1556 /*
1557 * The Connection/SSH/Tunnels panel.
1558 */
1559 ctrl_settitle(b, "Connection/SSH/Tunnels",
1560 "Options controlling SSH tunnelling");
1561
1562 s = ctrl_getset(b, "Connection/SSH/Tunnels", "x11", "X11 forwarding");
1563 ctrl_checkbox(s, "Enable X11 forwarding", 'e',
1564 HELPCTX(ssh_tunnels_x11),
1565 dlg_stdcheckbox_handler,I(offsetof(Config,x11_forward)));
1566 ctrl_editbox(s, "X display location", 'x', 50,
1567 HELPCTX(ssh_tunnels_x11),
1568 dlg_stdeditbox_handler, I(offsetof(Config,x11_display)),
1569 I(sizeof(((Config *)0)->x11_display)));
1570 ctrl_radiobuttons(s, "Remote X11 authentication protocol", 'u', 2,
1571 HELPCTX(ssh_tunnels_x11auth),
1572 dlg_stdradiobutton_handler,
1573 I(offsetof(Config, x11_auth)),
1574 "MIT-Magic-Cookie-1", I(X11_MIT),
1575 "XDM-Authorization-1", I(X11_XDM), NULL);
1576
1577 s = ctrl_getset(b, "Connection/SSH/Tunnels", "portfwd",
1578 "Port forwarding");
1579 ctrl_checkbox(s, "Local ports accept connections from other hosts",'t',
1580 HELPCTX(ssh_tunnels_portfwd_localhost),
1581 dlg_stdcheckbox_handler,
1582 I(offsetof(Config,lport_acceptall)));
1583 ctrl_checkbox(s, "Remote ports do the same (SSH v2 only)", 'p',
1584 HELPCTX(ssh_tunnels_portfwd_localhost),
1585 dlg_stdcheckbox_handler,
1586 I(offsetof(Config,rport_acceptall)));
1587
1588 ctrl_columns(s, 3, 55, 20, 25);
1589 c = ctrl_text(s, "Forwarded ports:", HELPCTX(ssh_tunnels_portfwd));
1590 c->generic.column = COLUMN_FIELD(0,2);
1591 /* You want to select from the list, _then_ hit Remove. So tab order
1592 * should be that way round. */
1593 pfd = (struct portfwd_data *)ctrl_alloc(b,sizeof(struct portfwd_data));
1594 pfd->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1595 HELPCTX(ssh_tunnels_portfwd),
1596 portfwd_handler, P(pfd));
1597 pfd->rembutton->generic.column = 2;
1598 pfd->rembutton->generic.tabdelay = 1;
1599 pfd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1600 HELPCTX(ssh_tunnels_portfwd),
1601 portfwd_handler, P(pfd));
1602 pfd->listbox->listbox.height = 3;
1603 pfd->listbox->listbox.ncols = 2;
1604 pfd->listbox->listbox.percentages = snewn(2, int);
1605 pfd->listbox->listbox.percentages[0] = 20;
1606 pfd->listbox->listbox.percentages[1] = 80;
1607 ctrl_tabdelay(s, pfd->rembutton);
1608 ctrl_text(s, "Add new forwarded port:", HELPCTX(ssh_tunnels_portfwd));
1609 /* You want to enter source, destination and type, _then_ hit Add.
1610 * Again, we adjust the tab order to reflect this. */
1611 pfd->addbutton = ctrl_pushbutton(s, "Add", 'd',
1612 HELPCTX(ssh_tunnels_portfwd),
1613 portfwd_handler, P(pfd));
1614 pfd->addbutton->generic.column = 2;
1615 pfd->addbutton->generic.tabdelay = 1;
1616 pfd->sourcebox = ctrl_editbox(s, "Source port", 's', 40,
1617 HELPCTX(ssh_tunnels_portfwd),
1618 portfwd_handler, P(pfd), P(NULL));
1619 pfd->sourcebox->generic.column = 0;
1620 pfd->destbox = ctrl_editbox(s, "Destination", 'i', 67,
1621 HELPCTX(ssh_tunnels_portfwd),
1622 portfwd_handler, P(pfd), P(NULL));
1623 pfd->direction = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
1624 HELPCTX(ssh_tunnels_portfwd),
1625 portfwd_handler, P(pfd),
1626 "Local", 'l', P(NULL),
1627 "Remote", 'm', P(NULL),
1628 "Dynamic", 'y', P(NULL),
1629 NULL);
1630 ctrl_tabdelay(s, pfd->addbutton);
1631 ctrl_columns(s, 1, 100);
1632
1633 /*
1634 * The Connection/SSH/Bugs panel.
1635 */
1636 ctrl_settitle(b, "Connection/SSH/Bugs",
1637 "Workarounds for SSH server bugs");
1638
1639 s = ctrl_getset(b, "Connection/SSH/Bugs", "main",
1640 "Detection of known bugs in SSH servers");
1641 ctrl_droplist(s, "Chokes on SSH1 ignore messages", 'i', 20,
1642 HELPCTX(ssh_bugs_ignore1),
1643 sshbug_handler, I(offsetof(Config,sshbug_ignore1)));
1644 ctrl_droplist(s, "Refuses all SSH1 password camouflage", 's', 20,
1645 HELPCTX(ssh_bugs_plainpw1),
1646 sshbug_handler, I(offsetof(Config,sshbug_plainpw1)));
1647 ctrl_droplist(s, "Chokes on SSH1 RSA authentication", 'r', 20,
1648 HELPCTX(ssh_bugs_rsa1),
1649 sshbug_handler, I(offsetof(Config,sshbug_rsa1)));
1650 ctrl_droplist(s, "Miscomputes SSH2 HMAC keys", 'm', 20,
1651 HELPCTX(ssh_bugs_hmac2),
1652 sshbug_handler, I(offsetof(Config,sshbug_hmac2)));
1653 ctrl_droplist(s, "Miscomputes SSH2 encryption keys", 'e', 20,
1654 HELPCTX(ssh_bugs_derivekey2),
1655 sshbug_handler, I(offsetof(Config,sshbug_derivekey2)));
1656 ctrl_droplist(s, "Requires padding on SSH2 RSA signatures", 'p', 20,
1657 HELPCTX(ssh_bugs_rsapad2),
1658 sshbug_handler, I(offsetof(Config,sshbug_rsapad2)));
1659 ctrl_droplist(s, "Chokes on Diffie-Hellman group exchange", 'd', 20,
1660 HELPCTX(ssh_bugs_dhgex2),
1661 sshbug_handler, I(offsetof(Config,sshbug_dhgex2)));
1662 ctrl_droplist(s, "Misuses the session ID in PK auth", 'n', 20,
1663 HELPCTX(ssh_bugs_pksessid2),
1664 sshbug_handler, I(offsetof(Config,sshbug_pksessid2)));
1665 }
1666 }