]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - config.c
ebcd6077ea964b816ac5acfa14a9fa4812614c17
[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(ctrl, 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(ctrl, 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
984     /*
985      * The Window/Appearance panel.
986      */
987     ctrl_settitle(b, "Window/Appearance",
988                   "Configure the appearance of PuTTY's window");
989
990     s = ctrl_getset(b, "Window/Appearance", "cursor",
991                     "Adjust the use of the cursor");
992     ctrl_radiobuttons(s, "Cursor appearance:", NO_SHORTCUT, 3,
993                       HELPCTX(appearance_cursor),
994                       dlg_stdradiobutton_handler,
995                       I(offsetof(Config, cursor_type)),
996                       "Block", 'l', I(0),
997                       "Underline", 'u', I(1),
998                       "Vertical line", 'v', I(2), NULL);
999     ctrl_checkbox(s, "Cursor blinks", 'b',
1000                   HELPCTX(appearance_cursor),
1001                   dlg_stdcheckbox_handler, I(offsetof(Config,blink_cur)));
1002
1003     s = ctrl_getset(b, "Window/Appearance", "font",
1004                     "Font settings");
1005     ctrl_fontsel(s, "Font used in the terminal window", 'n',
1006                  HELPCTX(appearance_font),
1007                  dlg_stdfontsel_handler, I(offsetof(Config, font)));
1008
1009     s = ctrl_getset(b, "Window/Appearance", "mouse",
1010                     "Adjust the use of the mouse pointer");
1011     ctrl_checkbox(s, "Hide mouse pointer when typing in window", 'p',
1012                   HELPCTX(appearance_hidemouse),
1013                   dlg_stdcheckbox_handler, I(offsetof(Config,hide_mouseptr)));
1014
1015     s = ctrl_getset(b, "Window/Appearance", "border",
1016                     "Adjust the window border");
1017     ctrl_editbox(s, "Gap between text and window edge:", NO_SHORTCUT, 20,
1018                  HELPCTX(appearance_border),
1019                  dlg_stdeditbox_handler,
1020                  I(offsetof(Config,window_border)), I(-1));
1021
1022     /*
1023      * The Window/Behaviour panel.
1024      */
1025     ctrl_settitle(b, "Window/Behaviour",
1026                   "Configure the behaviour of PuTTY's window");
1027
1028     s = ctrl_getset(b, "Window/Behaviour", "title",
1029                     "Adjust the behaviour of the window title");
1030     ctrl_editbox(s, "Window title:", 't', 100,
1031                  HELPCTX(appearance_title),
1032                  dlg_stdeditbox_handler, I(offsetof(Config,wintitle)),
1033                  I(sizeof(((Config *)0)->wintitle)));
1034     ctrl_checkbox(s, "Separate window and icon titles", 'i',
1035                   HELPCTX(appearance_title),
1036                   dlg_stdcheckbox_handler,
1037                   I(CHECKBOX_INVERT | offsetof(Config,win_name_always)));
1038
1039     s = ctrl_getset(b, "Window/Behaviour", "main", NULL);
1040     ctrl_checkbox(s, "Warn before closing window", 'w',
1041                   HELPCTX(behaviour_closewarn),
1042                   dlg_stdcheckbox_handler, I(offsetof(Config,warn_on_close)));
1043
1044     /*
1045      * The Window/Translation panel.
1046      */
1047     ctrl_settitle(b, "Window/Translation",
1048                   "Options controlling character set translation");
1049
1050     s = ctrl_getset(b, "Window/Translation", "trans",
1051                     "Character set translation on received data");
1052     ctrl_combobox(s, "Received data assumed to be in which character set:",
1053                   'r', 100, HELPCTX(translation_codepage),
1054                   codepage_handler, P(NULL), P(NULL));
1055
1056     s = ctrl_getset(b, "Window/Translation", "linedraw",
1057                     "Adjust how PuTTY displays line drawing characters");
1058     ctrl_radiobuttons(s, "Handling of line drawing characters:", NO_SHORTCUT,1,
1059                       HELPCTX(translation_linedraw),
1060                       dlg_stdradiobutton_handler,
1061                       I(offsetof(Config, vtmode)),
1062                       "Font has XWindows encoding", 'x', I(VT_XWINDOWS),
1063                       "Poor man's line drawing (+, - and |)",'p',I(VT_POORMAN),
1064                       "Unicode mode", 'u', I(VT_UNICODE), NULL);
1065
1066     /*
1067      * The Window/Selection panel.
1068      */
1069     ctrl_settitle(b, "Window/Selection", "Options controlling copy and paste");
1070
1071     s = ctrl_getset(b, "Window/Selection", "trans",
1072                     "Translation of pasted characters");
1073     ctrl_checkbox(s, "Don't translate line drawing chars into +, - and |",'d',
1074                   HELPCTX(selection_linedraw),
1075                   dlg_stdcheckbox_handler, I(offsetof(Config,rawcnp)));
1076         
1077     s = ctrl_getset(b, "Window/Selection", "mouse",
1078                     "Control use of mouse");
1079     ctrl_checkbox(s, "Shift overrides application's use of mouse", 'p',
1080                   HELPCTX(selection_shiftdrag),
1081                   dlg_stdcheckbox_handler, I(offsetof(Config,mouse_override)));
1082     ctrl_radiobuttons(s,
1083                       "Default selection mode (Alt+drag does the other one):",
1084                       NO_SHORTCUT, 2,
1085                       HELPCTX(selection_rect),
1086                       dlg_stdradiobutton_handler,
1087                       I(offsetof(Config, rect_select)),
1088                       "Normal", 'n', I(0),
1089                       "Rectangular block", 'r', I(1), NULL);
1090
1091     s = ctrl_getset(b, "Window/Selection", "charclass",
1092                     "Control the select-one-word-at-a-time mode");
1093     ccd = (struct charclass_data *)
1094         ctrl_alloc(b, sizeof(struct charclass_data));
1095     ccd->listbox = ctrl_listbox(s, "Character classes:", 'e',
1096                                 HELPCTX(selection_charclasses),
1097                                 charclass_handler, P(ccd));
1098     ccd->listbox->listbox.multisel = 1;
1099     ccd->listbox->listbox.ncols = 4;
1100     ccd->listbox->listbox.percentages = smalloc(4*sizeof(int));
1101     ccd->listbox->listbox.percentages[0] = 15;
1102     ccd->listbox->listbox.percentages[1] = 25;
1103     ccd->listbox->listbox.percentages[2] = 20;
1104     ccd->listbox->listbox.percentages[3] = 40;
1105     ctrl_columns(s, 2, 67, 33);
1106     ccd->editbox = ctrl_editbox(s, "Set to class", 't', 50,
1107                                 HELPCTX(selection_charclasses),
1108                                 charclass_handler, P(ccd), P(NULL));
1109     ccd->editbox->generic.column = 0;
1110     ccd->button = ctrl_pushbutton(s, "Set", 's',
1111                                   HELPCTX(selection_charclasses),
1112                                   charclass_handler, P(ccd));
1113     ccd->button->generic.column = 1;
1114     ctrl_columns(s, 1, 100);
1115
1116     /*
1117      * The Window/Colours panel.
1118      */
1119     ctrl_settitle(b, "Window/Colours", "Options controlling use of colours");
1120
1121     s = ctrl_getset(b, "Window/Colours", "general",
1122                     "General options for colour usage");
1123     ctrl_checkbox(s, "Bolded text is a different colour", 'b',
1124                   HELPCTX(colours_bold),
1125                   dlg_stdcheckbox_handler, I(offsetof(Config,bold_colour)));
1126
1127     s = ctrl_getset(b, "Window/Colours", "adjust",
1128                     "Adjust the precise colours PuTTY displays");
1129     ctrl_text(s, "Select a colour from the list, and then click the"
1130               " Modify button to change its appearance.",
1131               HELPCTX(colours_config));
1132     ctrl_columns(s, 2, 67, 33);
1133     cd = (struct colour_data *)ctrl_alloc(b, sizeof(struct colour_data));
1134     cd->listbox = ctrl_listbox(s, "Select a colour to adjust:", 'u',
1135                                HELPCTX(colours_config), colour_handler, P(cd));
1136     cd->listbox->generic.column = 0;
1137     c = ctrl_text(s, "RGB value:", HELPCTX(colours_config));
1138     c->generic.column = 1;
1139     cd->rgbtext = ctrl_text(s, "00/00/00", HELPCTX(colours_config));
1140     cd->rgbtext->generic.column = 1;
1141     cd->button = ctrl_pushbutton(s, "Modify", 'm', HELPCTX(colours_config),
1142                                  colour_handler, P(cd));
1143     cd->button->generic.column = 1;
1144     ctrl_columns(s, 1, 100);
1145
1146     /*
1147      * The Connection panel.
1148      */
1149     ctrl_settitle(b, "Connection", "Options controlling the connection");
1150
1151     if (!midsession) {
1152         s = ctrl_getset(b, "Connection", "data", "Data to send to the server");
1153         ctrl_editbox(s, "Terminal-type string", 't', 50,
1154                      HELPCTX(connection_termtype),
1155                      dlg_stdeditbox_handler, I(offsetof(Config,termtype)),
1156                      I(sizeof(((Config *)0)->termtype)));
1157         ctrl_editbox(s, "Auto-login username", 'u', 50,
1158                      HELPCTX(connection_username),
1159                      dlg_stdeditbox_handler, I(offsetof(Config,username)),
1160                      I(sizeof(((Config *)0)->username)));
1161     }
1162
1163     s = ctrl_getset(b, "Connection", "keepalive",
1164                     "Sending of null packets to keep session active");
1165     ctrl_editbox(s, "Seconds between keepalives (0 to turn off)", 'k', 20,
1166                  HELPCTX(connection_keepalive),
1167                  dlg_stdeditbox_handler, I(offsetof(Config,ping_interval)),
1168                  I(-1));
1169
1170     if (!midsession) {
1171         s = ctrl_getset(b, "Connection", "tcp",
1172                         "Low-level TCP connection options");
1173         ctrl_checkbox(s, "Disable Nagle's algorithm (TCP_NODELAY option)", 'n',
1174                       HELPCTX(connection_nodelay),
1175                       dlg_stdcheckbox_handler,
1176                       I(offsetof(Config,tcp_nodelay)));
1177     }
1178
1179     if (!midsession) {
1180         /*
1181          * The Connection/Proxy panel.
1182          */
1183         ctrl_settitle(b, "Connection/Proxy",
1184                       "Options controlling proxy usage");
1185
1186         s = ctrl_getset(b, "Connection/Proxy", "basics", "Proxy basics");
1187         ctrl_radiobuttons(s, "Proxy type:", NO_SHORTCUT, 4,
1188                           HELPCTX(proxy_type),
1189                           dlg_stdradiobutton_handler,
1190                           I(offsetof(Config, proxy_type)),
1191                           "None", 'n', I(PROXY_NONE),
1192                           "HTTP", 't', I(PROXY_HTTP),
1193                           "SOCKS", 's', I(PROXY_SOCKS),
1194                           "Telnet", 'l', I(PROXY_TELNET),
1195                           NULL);
1196         ctrl_columns(s, 2, 80, 20);
1197         c = ctrl_editbox(s, "Proxy hostname", 'y', 100,
1198                          HELPCTX(proxy_main),
1199                          dlg_stdeditbox_handler,
1200                          I(offsetof(Config,proxy_host)),
1201                          I(sizeof(((Config *)0)->proxy_host)));
1202         c->generic.column = 0;
1203         c = ctrl_editbox(s, "Port", 'p', 100,
1204                          HELPCTX(proxy_main),
1205                          dlg_stdeditbox_handler,
1206                          I(offsetof(Config,proxy_port)),
1207                          I(-1));
1208         c->generic.column = 1;
1209         ctrl_columns(s, 1, 100);
1210         ctrl_editbox(s, "Exclude Hosts/IPs", 'e', 100,
1211                      HELPCTX(proxy_exclude),
1212                      dlg_stdeditbox_handler,
1213                      I(offsetof(Config,proxy_exclude_list)),
1214                      I(sizeof(((Config *)0)->proxy_exclude_list)));
1215         ctrl_checkbox(s, "Consider proxying local host connections", 'x',
1216                       HELPCTX(proxy_exclude),
1217                       dlg_stdcheckbox_handler,
1218                       I(offsetof(Config,even_proxy_localhost)));
1219         ctrl_radiobuttons(s, "Do DNS name lookup at proxy end:", 'd', 3,
1220                           HELPCTX(proxy_dns),
1221                           dlg_stdradiobutton_handler,
1222                           I(offsetof(Config, proxy_dns)),
1223                           "No", I(FORCE_OFF),
1224                           "Auto", I(AUTO),
1225                           "Yes", I(FORCE_ON), NULL);
1226         ctrl_editbox(s, "Username", 'u', 60,
1227                      HELPCTX(proxy_auth),
1228                      dlg_stdeditbox_handler,
1229                      I(offsetof(Config,proxy_username)),
1230                      I(sizeof(((Config *)0)->proxy_username)));
1231         c = ctrl_editbox(s, "Password", 'w', 60,
1232                          HELPCTX(proxy_auth),
1233                          dlg_stdeditbox_handler,
1234                          I(offsetof(Config,proxy_password)),
1235                          I(sizeof(((Config *)0)->proxy_password)));
1236         c->editbox.password = 1;
1237
1238         s = ctrl_getset(b, "Connection/Proxy", "misc",
1239                         "Miscellaneous proxy settings");
1240         ctrl_editbox(s, "Telnet command", 'm', 100,
1241                      HELPCTX(proxy_command),
1242                      dlg_stdeditbox_handler,
1243                      I(offsetof(Config,proxy_telnet_command)),
1244                      I(sizeof(((Config *)0)->proxy_telnet_command)));
1245         ctrl_radiobuttons(s, "SOCKS Version", 'v', 2,
1246                           HELPCTX(proxy_socksver),
1247                           dlg_stdradiobutton_handler,
1248                           I(offsetof(Config, proxy_socks_version)),
1249                           "Version 5", I(5), "Version 4", I(4), NULL);
1250     }
1251
1252     /*
1253      * The Telnet panel exists in the base config box, and in a
1254      * mid-session reconfig box _if_ we're using Telnet.
1255      */
1256     if (!midsession || protocol == PROT_TELNET) {
1257         /*
1258          * The Connection/Telnet panel.
1259          */
1260         ctrl_settitle(b, "Connection/Telnet",
1261                       "Options controlling Telnet connections");
1262
1263         if (!midsession) {
1264             s = ctrl_getset(b, "Connection/Telnet", "data",
1265                             "Data to send to the server");
1266             ctrl_editbox(s, "Terminal-speed string", 's', 50,
1267                          HELPCTX(telnet_termspeed),
1268                          dlg_stdeditbox_handler, I(offsetof(Config,termspeed)),
1269                          I(sizeof(((Config *)0)->termspeed)));
1270             ctrl_text(s, "Environment variables:", HELPCTX(telnet_environ));
1271             ctrl_columns(s, 2, 80, 20);
1272             ed = (struct environ_data *)
1273                 ctrl_alloc(b, sizeof(struct environ_data));
1274             ed->varbox = ctrl_editbox(s, "Variable", 'v', 60,
1275                                       HELPCTX(telnet_environ),
1276                                       environ_handler, P(ed), P(NULL));
1277             ed->varbox->generic.column = 0;
1278             ed->valbox = ctrl_editbox(s, "Value", 'l', 60,
1279                                       HELPCTX(telnet_environ),
1280                                       environ_handler, P(ed), P(NULL));
1281             ed->valbox->generic.column = 0;
1282             ed->addbutton = ctrl_pushbutton(s, "Add", 'd',
1283                                             HELPCTX(telnet_environ),
1284                                             environ_handler, P(ed));
1285             ed->addbutton->generic.column = 1;
1286             ed->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1287                                             HELPCTX(telnet_environ),
1288                                             environ_handler, P(ed));
1289             ed->rembutton->generic.column = 1;
1290             ctrl_columns(s, 1, 100);
1291             ed->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1292                                        HELPCTX(telnet_environ),
1293                                        environ_handler, P(ed));
1294             ed->listbox->listbox.height = 3;
1295         }
1296
1297         s = ctrl_getset(b, "Connection/Telnet", "protocol",
1298                         "Telnet protocol adjustments");
1299
1300         if (!midsession) {
1301             ctrl_radiobuttons(s, "Handling of OLD_ENVIRON ambiguity:",
1302                               NO_SHORTCUT, 2,
1303                               HELPCTX(telnet_oldenviron),
1304                               dlg_stdradiobutton_handler,
1305                               I(offsetof(Config, rfc_environ)),
1306                               "BSD (commonplace)", 'b', I(0),
1307                               "RFC 1408 (unusual)", 'f', I(1), NULL);
1308             ctrl_radiobuttons(s, "Telnet negotiation mode:", 't', 2,
1309                               HELPCTX(telnet_passive),
1310                               dlg_stdradiobutton_handler,
1311                               I(offsetof(Config, passive_telnet)),
1312                               "Passive", I(1), "Active", I(0), NULL);
1313         }
1314         ctrl_checkbox(s, "Keyboard sends telnet Backspace and Interrupt", 'k',
1315                       HELPCTX(telnet_specialkeys),
1316                       dlg_stdcheckbox_handler,
1317                       I(offsetof(Config,telnet_keyboard)));
1318         ctrl_checkbox(s, "Return key sends telnet New Line instead of ^M",
1319                       NO_SHORTCUT, HELPCTX(telnet_newline),
1320                       dlg_stdcheckbox_handler,
1321                       I(offsetof(Config,telnet_newline)));
1322     }
1323
1324     if (!midsession) {
1325
1326         /*
1327          * The Connection/Rlogin panel.
1328          */
1329         ctrl_settitle(b, "Connection/Rlogin",
1330                       "Options controlling Rlogin connections");
1331
1332         s = ctrl_getset(b, "Connection/Rlogin", "data",
1333                         "Data to send to the server");
1334         ctrl_editbox(s, "Terminal-speed string", 's', 50,
1335                      HELPCTX(rlogin_termspeed),
1336                      dlg_stdeditbox_handler, I(offsetof(Config,termspeed)),
1337                      I(sizeof(((Config *)0)->termspeed)));
1338         ctrl_editbox(s, "Local username:", 'l', 50,
1339                      HELPCTX(rlogin_localuser),
1340                      dlg_stdeditbox_handler, I(offsetof(Config,localusername)),
1341                      I(sizeof(((Config *)0)->localusername)));
1342
1343     }
1344
1345     /*
1346      * All the SSH stuff is omitted in PuTTYtel.
1347      */
1348
1349     if (!midsession && backends[3].backend != NULL) {
1350
1351         /*
1352          * The Connection/SSH panel.
1353          */
1354         ctrl_settitle(b, "Connection/SSH",
1355                       "Options controlling SSH connections");
1356
1357         s = ctrl_getset(b, "Connection/SSH", "data",
1358                         "Data to send to the server");
1359         ctrl_editbox(s, "Remote command:", 'r', 100,
1360                      HELPCTX(ssh_command),
1361                      dlg_stdeditbox_handler, I(offsetof(Config,remote_cmd)),
1362                      I(sizeof(((Config *)0)->remote_cmd)));
1363
1364         s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options");
1365         ctrl_checkbox(s, "Don't allocate a pseudo-terminal", 'p',
1366                       HELPCTX(ssh_nopty),
1367                       dlg_stdcheckbox_handler,
1368                       I(offsetof(Config,nopty)));
1369         ctrl_checkbox(s, "Enable compression", 'e',
1370                       HELPCTX(ssh_compress),
1371                       dlg_stdcheckbox_handler,
1372                       I(offsetof(Config,compression)));
1373         ctrl_radiobuttons(s, "Preferred SSH protocol version:", NO_SHORTCUT, 4,
1374                           HELPCTX(ssh_protocol),
1375                           dlg_stdradiobutton_handler,
1376                           I(offsetof(Config, sshprot)),
1377                           "1 only", 'l', I(0),
1378                           "1", '1', I(1),
1379                           "2", '2', I(2),
1380                           "2 only", 'n', I(3), NULL);
1381
1382         s = ctrl_getset(b, "Connection/SSH", "encryption", "Encryption options");
1383         ctrl_draglist(s, "Encryption cipher selection policy:", 's',
1384                       HELPCTX(ssh_ciphers),
1385                       cipherlist_handler, P(NULL));
1386         ctrl_checkbox(s, "Enable non-standard use of single-DES in SSH 2", 'i',
1387                       HELPCTX(ssh_ciphers),
1388                       dlg_stdcheckbox_handler,
1389                       I(offsetof(Config,ssh2_des_cbc)));
1390
1391         /*
1392          * The Connection/SSH/Auth panel.
1393          */
1394         ctrl_settitle(b, "Connection/SSH/Auth",
1395                       "Options controlling SSH authentication");
1396
1397         s = ctrl_getset(b, "Connection/SSH/Auth", "methods",
1398                         "Authentication methods");
1399         ctrl_checkbox(s, "Attempt TIS or CryptoCard auth (SSH1)", 'm',
1400                       HELPCTX(ssh_auth_tis),
1401                       dlg_stdcheckbox_handler,
1402                       I(offsetof(Config,try_tis_auth)));
1403         ctrl_checkbox(s, "Attempt \"keyboard-interactive\" auth (SSH2)",
1404                       'i', HELPCTX(ssh_auth_ki),
1405                       dlg_stdcheckbox_handler,
1406                       I(offsetof(Config,try_ki_auth)));
1407
1408         s = ctrl_getset(b, "Connection/SSH/Auth", "params",
1409                         "Authentication parameters");
1410         ctrl_checkbox(s, "Allow agent forwarding", 'f',
1411                       HELPCTX(ssh_auth_agentfwd),
1412                       dlg_stdcheckbox_handler, I(offsetof(Config,agentfwd)));
1413         ctrl_checkbox(s, "Allow attempted changes of username in SSH2", 'u',
1414                       HELPCTX(ssh_auth_changeuser),
1415                       dlg_stdcheckbox_handler,
1416                       I(offsetof(Config,change_username)));
1417         ctrl_filesel(s, "Private key file for authentication:", 'k',
1418                      FILTER_KEY_FILES, FALSE, "Select private key file",
1419                      HELPCTX(ssh_auth_privkey),
1420                      dlg_stdfilesel_handler, I(offsetof(Config, keyfile)));
1421
1422         /*
1423          * The Connection/SSH/Tunnels panel.
1424          */
1425         ctrl_settitle(b, "Connection/SSH/Tunnels",
1426                       "Options controlling SSH tunnelling");
1427
1428         s = ctrl_getset(b, "Connection/SSH/Tunnels", "x11", "X11 forwarding");
1429         ctrl_checkbox(s, "Enable X11 forwarding", 'e',
1430                       HELPCTX(ssh_tunnels_x11),
1431                       dlg_stdcheckbox_handler,I(offsetof(Config,x11_forward)));
1432         ctrl_editbox(s, "X display location", 'x', 50,
1433                      HELPCTX(ssh_tunnels_x11),
1434                      dlg_stdeditbox_handler, I(offsetof(Config,x11_display)),
1435                      I(sizeof(((Config *)0)->x11_display)));
1436         ctrl_radiobuttons(s, "Remote X11 authentication protocol", 'u', 2,
1437                           HELPCTX(ssh_tunnels_x11auth),
1438                           dlg_stdradiobutton_handler,
1439                           I(offsetof(Config, x11_auth)),
1440                           "MIT-Magic-Cookie-1", I(X11_MIT),
1441                           "XDM-Authorization-1", I(X11_XDM), NULL);
1442
1443         s = ctrl_getset(b, "Connection/SSH/Tunnels", "portfwd",
1444                         "Port forwarding");
1445         ctrl_checkbox(s, "Local ports accept connections from other hosts",'t',
1446                       HELPCTX(ssh_tunnels_portfwd_localhost),
1447                       dlg_stdcheckbox_handler,
1448                       I(offsetof(Config,lport_acceptall)));
1449         ctrl_checkbox(s, "Remote ports do the same (SSH v2 only)", 'p',
1450                       HELPCTX(ssh_tunnels_portfwd_localhost),
1451                       dlg_stdcheckbox_handler,
1452                       I(offsetof(Config,rport_acceptall)));
1453
1454         ctrl_columns(s, 3, 55, 20, 25);
1455         c = ctrl_text(s, "Forwarded ports:", HELPCTX(ssh_tunnels_portfwd));
1456         c->generic.column = COLUMN_FIELD(0,2);
1457         /* You want to select from the list, _then_ hit Remove. So tab order
1458          * should be that way round. */
1459         pfd = (struct portfwd_data *)ctrl_alloc(b,sizeof(struct portfwd_data));
1460         pfd->rembutton = ctrl_pushbutton(s, "Remove", 'r',
1461                                          HELPCTX(ssh_tunnels_portfwd),
1462                                          portfwd_handler, P(pfd));
1463         pfd->rembutton->generic.column = 2;
1464         pfd->rembutton->generic.tabdelay = 1;
1465         pfd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
1466                                     HELPCTX(ssh_tunnels_portfwd),
1467                                     portfwd_handler, P(pfd));
1468         pfd->listbox->listbox.height = 3;
1469         ctrl_tabdelay(s, pfd->rembutton);
1470         ctrl_text(s, "Add new forwarded port:", HELPCTX(ssh_tunnels_portfwd));
1471         /* You want to enter source, destination and type, _then_ hit Add.
1472          * Again, we adjust the tab order to reflect this. */
1473         pfd->addbutton = ctrl_pushbutton(s, "Add", 'd',
1474                                          HELPCTX(ssh_tunnels_portfwd),
1475                                          portfwd_handler, P(pfd));
1476         pfd->addbutton->generic.column = 2;
1477         pfd->addbutton->generic.tabdelay = 1;
1478         pfd->sourcebox = ctrl_editbox(s, "Source port", 's', 40,
1479                                       HELPCTX(ssh_tunnels_portfwd),
1480                                       portfwd_handler, P(pfd), P(NULL));
1481         pfd->sourcebox->generic.column = 0;
1482         pfd->destbox = ctrl_editbox(s, "Destination", 'i', 67,
1483                                     HELPCTX(ssh_tunnels_portfwd),
1484                                     portfwd_handler, P(pfd), P(NULL));
1485         pfd->direction = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 2,
1486                                            HELPCTX(ssh_tunnels_portfwd),
1487                                            portfwd_handler, P(pfd),
1488                                            "Local", 'l', P(NULL),
1489                                            "Remote", 'm', P(NULL), NULL);
1490         ctrl_tabdelay(s, pfd->addbutton);
1491         ctrl_columns(s, 1, 100);
1492
1493         /*
1494          * The Connection/SSH/Bugs panel.
1495          */
1496         ctrl_settitle(b, "Connection/SSH/Bugs",
1497                       "Workarounds for SSH server bugs");
1498
1499         s = ctrl_getset(b, "Connection/SSH/Bugs", "main",
1500                         "Detection of known bugs in SSH servers");
1501         ctrl_droplist(s, "Chokes on SSH1 ignore messages", 'i', 20,
1502                       HELPCTX(ssh_bugs_ignore1),
1503                       sshbug_handler, I(offsetof(Config,sshbug_ignore1)));
1504         ctrl_droplist(s, "Refuses all SSH1 password camouflage", 's', 20,
1505                       HELPCTX(ssh_bugs_plainpw1),
1506                       sshbug_handler, I(offsetof(Config,sshbug_plainpw1)));
1507         ctrl_droplist(s, "Chokes on SSH1 RSA authentication", 'r', 20,
1508                       HELPCTX(ssh_bugs_rsa1),
1509                       sshbug_handler, I(offsetof(Config,sshbug_rsa1)));
1510         ctrl_droplist(s, "Miscomputes SSH2 HMAC keys", 'm', 20,
1511                       HELPCTX(ssh_bugs_hmac2),
1512                       sshbug_handler, I(offsetof(Config,sshbug_hmac2)));
1513         ctrl_droplist(s, "Miscomputes SSH2 encryption keys", 'e', 20,
1514                       HELPCTX(ssh_bugs_derivekey2),
1515                       sshbug_handler, I(offsetof(Config,sshbug_derivekey2)));
1516         ctrl_droplist(s, "Requires padding on SSH2 RSA signatures", 'p', 20,
1517                       HELPCTX(ssh_bugs_rsapad2),
1518                       sshbug_handler, I(offsetof(Config,sshbug_rsapad2)));
1519         ctrl_droplist(s, "Chokes on Diffie-Hellman group exchange", 'd', 20,
1520                       HELPCTX(ssh_bugs_dhgex2),
1521                       sshbug_handler, I(offsetof(Config,sshbug_dhgex2)));
1522         ctrl_droplist(s, "Misuses the session ID in PK auth", 'n', 20,
1523                       HELPCTX(ssh_bugs_pksessid2),
1524                       sshbug_handler, I(offsetof(Config,sshbug_pksessid2)));
1525     }
1526 }