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