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