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