]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - windlg.c
Add ISO8859-2 / CP852 translation courtesy of Jaromir Filsak
[PuTTY.git] / windlg.c
1 #include <windows.h>
2 #include <commctrl.h>
3 #include <commdlg.h>
4 #ifndef AUTO_WINSOCK
5 #ifdef WINSOCK_TWO
6 #include <winsock2.h>
7 #else
8 #include <winsock.h>
9 #endif
10 #endif
11 #include <stdio.h>
12 #include <stdlib.h>
13
14 #include "ssh.h"
15 #include "putty.h"
16 #include "win_res.h"
17 #include "storage.h"
18
19 static char **events = NULL;
20 static int nevents = 0, negsize = 0;
21
22 static HWND logbox = NULL, abtbox = NULL;
23
24 static HINSTANCE hinst;
25
26 static int readytogo;
27
28 static void force_normal(HWND hwnd)
29 {
30     static int recurse = 0;
31
32     WINDOWPLACEMENT wp;
33
34     if(recurse) return;
35     recurse = 1;
36
37     wp.length = sizeof(wp);
38     if (GetWindowPlacement(hwnd, &wp))
39     {
40         wp.showCmd = SW_SHOWNORMAL;
41         SetWindowPlacement(hwnd, &wp);
42     }
43     recurse = 0;
44 }
45
46 static void MyGetDlgItemInt (HWND hwnd, int id, int *result) {
47     BOOL ok;
48     int n;
49     n = GetDlgItemInt (hwnd, id, &ok, FALSE);
50     if (ok)
51         *result = n;
52 }
53
54 static int CALLBACK LogProc (HWND hwnd, UINT msg,
55                              WPARAM wParam, LPARAM lParam) {
56     int i;
57
58     switch (msg) {
59       case WM_INITDIALOG:
60         for (i=0; i<nevents; i++)
61             SendDlgItemMessage (hwnd, IDN_LIST, LB_ADDSTRING,
62                                 0, (LPARAM)events[i]);
63         return 1;
64       case WM_COMMAND:
65         switch (LOWORD(wParam)) {
66           case IDOK:
67             logbox = NULL;
68             DestroyWindow (hwnd);
69             return 0;
70           case IDN_COPY:
71             if (HIWORD(wParam) == BN_CLICKED ||
72                 HIWORD(wParam) == BN_DOUBLECLICKED) {
73                 int selcount;
74                 int *selitems;
75                 selcount = SendDlgItemMessage(hwnd, IDN_LIST,
76                                               LB_GETSELCOUNT, 0, 0);
77                 selitems = malloc(selcount * sizeof(int));
78                 if (selitems) {
79                     int count = SendDlgItemMessage(hwnd, IDN_LIST,
80                                                    LB_GETSELITEMS,
81                                                    selcount, (LPARAM)selitems);
82                     int i;
83                     int size;
84                     char *clipdata;
85                     static unsigned char sel_nl[] = SEL_NL;
86
87                     if (count == 0) {  /* can't copy zero stuff */
88                         MessageBeep(0);
89                         break;
90                     }
91
92                     size = 0;
93                     for (i = 0; i < count; i++)
94                         size += strlen(events[selitems[i]]) + sizeof(sel_nl);
95
96                     clipdata = malloc(size);
97                     if (clipdata) {
98                         char *p = clipdata;
99                         for (i = 0; i < count; i++) {
100                             char *q = events[selitems[i]];
101                             int qlen = strlen(q);
102                             memcpy(p, q, qlen);
103                             p += qlen;
104                             memcpy(p, sel_nl, sizeof(sel_nl));
105                             p += sizeof(sel_nl);
106                         }
107                         write_clip(clipdata, size, TRUE);
108                         free(clipdata);
109                     }
110                     free(selitems);
111
112                     for (i = 0; i < nevents; i++)
113                         SendDlgItemMessage(hwnd, IDN_LIST, LB_SETSEL,
114                                            FALSE, i);
115                 }
116             }
117             return 0;
118         }
119         return 0;
120       case WM_CLOSE:
121         logbox = NULL;
122         DestroyWindow (hwnd);
123         return 0;
124     }
125     return 0;
126 }
127
128 static int CALLBACK LicenceProc (HWND hwnd, UINT msg,
129                                  WPARAM wParam, LPARAM lParam) {
130     switch (msg) {
131       case WM_INITDIALOG:
132         return 1;
133       case WM_COMMAND:
134         switch (LOWORD(wParam)) {
135           case IDOK:
136             EndDialog(hwnd, 1);
137             return 0;
138         }
139         return 0;
140       case WM_CLOSE:
141         EndDialog(hwnd, 1);
142         return 0;
143     }
144     return 0;
145 }
146
147 static int CALLBACK AboutProc (HWND hwnd, UINT msg,
148                                WPARAM wParam, LPARAM lParam) {
149     switch (msg) {
150       case WM_INITDIALOG:
151         SetDlgItemText (hwnd, IDA_VERSION, ver);
152         return 1;
153       case WM_COMMAND:
154         switch (LOWORD(wParam)) {
155           case IDOK:
156             abtbox = NULL;
157             DestroyWindow (hwnd);
158             return 0;
159           case IDA_LICENCE:
160             EnableWindow(hwnd, 0);
161             DialogBox (hinst, MAKEINTRESOURCE(IDD_LICENCEBOX),
162                        NULL, LicenceProc);
163             EnableWindow(hwnd, 1);
164             SetActiveWindow(hwnd);
165             return 0;
166         }
167         return 0;
168       case WM_CLOSE:
169         abtbox = NULL;
170         DestroyWindow (hwnd);
171         return 0;
172     }
173     return 0;
174 }
175
176 /* ----------------------------------------------------------------------
177  * Routines to self-manage the controls in a dialog box.
178  */
179
180 #define GAPBETWEEN 3
181 #define GAPWITHIN 1
182 #define GAPXBOX 7
183 #define GAPYBOX 4
184 #define DLGWIDTH 168
185 #define STATICHEIGHT 8
186 #define CHECKBOXHEIGHT 8
187 #define RADIOHEIGHT 8
188 #define EDITHEIGHT 12
189 #define COMBOHEIGHT 12
190 #define PUSHBTNHEIGHT 14
191
192 struct ctlpos {
193     HWND hwnd;
194     WPARAM font;
195     int dlu4inpix;
196     int ypos, width;
197     int xoff;
198     int boxystart, boxid, boxtextid;
199     char *boxtext;
200 };
201
202 static void ctlposinit(struct ctlpos *cp, HWND hwnd,
203                        int leftborder, int rightborder, int topborder) {
204     RECT r, r2;
205     cp->hwnd = hwnd;
206     cp->font = SendMessage(hwnd, WM_GETFONT, 0, 0);
207     cp->ypos = topborder;
208     GetClientRect(hwnd, &r);
209     r2.left = r2.top = 0;
210     r2.right = 4;
211     r2.bottom = 8;
212     MapDialogRect(hwnd, &r2);
213     cp->dlu4inpix = r2.right;
214     cp->width = (r.right * 4) / (r2.right) - 2*GAPBETWEEN;
215     cp->xoff = leftborder;
216     cp->width -= leftborder + rightborder;
217 }
218
219 static void doctl(struct ctlpos *cp, RECT r,
220                   char *wclass, int wstyle, int exstyle,
221                   char *wtext, int wid) {
222     HWND ctl;
223     /*
224      * Note nonstandard use of RECT. This is deliberate: by
225      * transforming the width and height directly we arrange to
226      * have all supposedly same-sized controls really same-sized.
227      */
228
229     r.left += cp->xoff;
230     MapDialogRect(cp->hwnd, &r);
231
232     ctl = CreateWindowEx(exstyle, wclass, wtext, wstyle,
233                          r.left, r.top, r.right, r.bottom,
234                          cp->hwnd, (HMENU)wid, hinst, NULL);
235     SendMessage(ctl, WM_SETFONT, cp->font, MAKELPARAM(TRUE, 0));
236 }
237
238 /*
239  * A title bar across the top of a sub-dialog.
240  */
241 static void bartitle(struct ctlpos *cp, char *name, int id) {
242     RECT r;
243
244     r.left = GAPBETWEEN; r.right = cp->width;
245     r.top = cp->ypos; r.bottom = STATICHEIGHT;
246     cp->ypos += r.bottom + GAPBETWEEN;
247     doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, name, id);
248 }
249
250 /*
251  * Begin a grouping box, with or without a group title.
252  */
253 static void beginbox(struct ctlpos *cp, char *name, int idbox, int idtext) {
254     if (name)
255         cp->ypos += STATICHEIGHT/2;
256     cp->boxystart = cp->ypos;
257     if (name)
258         cp->ypos += STATICHEIGHT - (STATICHEIGHT/2);
259     cp->ypos += GAPYBOX;
260     cp->width -= 2*GAPXBOX;
261     cp->xoff += GAPXBOX;
262     cp->boxid = idbox;
263     cp->boxtextid = idtext;
264     cp->boxtext = name;
265 }
266
267 /*
268  * End a grouping box.
269  */
270 static void endbox(struct ctlpos *cp) {
271     RECT r;
272     cp->xoff -= GAPXBOX;
273     cp->width += 2*GAPXBOX;
274     cp->ypos += GAPYBOX - GAPBETWEEN;
275     r.left = GAPBETWEEN; r.right = cp->width;
276     r.top = cp->boxystart; r.bottom = cp->ypos - cp->boxystart;
277     doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE | SS_ETCHEDFRAME, 0,
278           "", cp->boxid);
279     if (cp->boxtext) {
280         SIZE s;
281         HDC hdc;
282         HFONT oldfont, dlgfont;
283         hdc = GetDC(cp->hwnd);
284         dlgfont = (HFONT)cp->font;
285         oldfont = SelectObject(hdc, dlgfont);
286         GetTextExtentPoint32(hdc, cp->boxtext, strlen(cp->boxtext), &s);
287         SelectObject(hdc, oldfont);
288         DeleteDC(hdc);
289         r.left = GAPXBOX + GAPBETWEEN;
290         r.right = (s.cx * 4 + cp->dlu4inpix-1) / cp->dlu4inpix;
291         
292         r.top = cp->boxystart - STATICHEIGHT/2; r.bottom = STATICHEIGHT;
293         doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0,
294               cp->boxtext, cp->boxtextid);
295     }
296     cp->ypos += GAPYBOX;
297 }
298
299 /*
300  * Some edit boxes. Each one has a static above it. The percentages
301  * of the horizontal space are provided.
302  */
303 static void multiedit(struct ctlpos *cp, ...) {
304     RECT r;
305     va_list ap;
306     int percent, xpos;
307
308     percent = xpos = 0;
309     va_start(ap, cp);
310     while (1) {
311         char *text;
312         int staticid, editid, pcwidth;
313         text = va_arg(ap, char *);
314         if (!text)
315             break;
316         staticid = va_arg(ap, int);
317         editid = va_arg(ap, int);
318         pcwidth = va_arg(ap, int);
319
320         r.left = xpos + GAPBETWEEN;
321         percent += pcwidth;
322         xpos = (cp->width + GAPBETWEEN) * percent / 100;
323         r.right = xpos - r.left;
324
325         r.top = cp->ypos; r.bottom = STATICHEIGHT;
326         doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0,
327               text, staticid);
328         r.top = cp->ypos + 8 + GAPWITHIN; r.bottom = EDITHEIGHT;
329         doctl(cp, r, "EDIT",
330               WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
331               WS_EX_CLIENTEDGE,
332               "", editid);
333     }
334     va_end(ap);
335     cp->ypos += 8+GAPWITHIN+12+GAPBETWEEN;
336 }
337
338 /*
339  * A set of radio buttons on the same line, with a static above
340  * them. `nacross' dictates how many parts the line is divided into
341  * (you might want this not to equal the number of buttons if you
342  * needed to line up some 2s and some 3s to look good in the same
343  * panel).
344  */
345 static void radioline(struct ctlpos *cp,
346                       char *text, int id, int nacross, ...) {
347     RECT r;
348     va_list ap;
349     int group;
350     int i;
351
352     r.left = GAPBETWEEN; r.top = cp->ypos;
353     r.right = cp->width; r.bottom = STATICHEIGHT;
354     cp->ypos += r.bottom + GAPWITHIN;
355     doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, text, id);
356     va_start(ap, nacross);
357     group = WS_GROUP;
358     i = 0;
359     while (1) {
360         char *btext;
361         int bid;
362         btext = va_arg(ap, char *);
363         if (!btext)
364             break;
365         bid = va_arg(ap, int);
366         r.left = GAPBETWEEN + i * (cp->width+GAPBETWEEN)/nacross;
367         r.right = (i+1) * (cp->width+GAPBETWEEN)/nacross - r.left;
368         r.top = cp->ypos; r.bottom = RADIOHEIGHT;
369         doctl(cp, r, "BUTTON",
370               BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP | group,
371               0,
372               btext, bid);
373         group = 0;
374         i++;
375     }
376     va_end(ap);
377     cp->ypos += r.bottom + GAPBETWEEN;
378 }
379
380 /*
381  * A set of radio buttons on multiple lines, with a static above
382  * them.
383  */
384 static void radiobig(struct ctlpos *cp, char *text, int id, ...) {
385     RECT r;
386     va_list ap;
387     int group;
388
389     r.left = GAPBETWEEN; r.top = cp->ypos;
390     r.right = cp->width; r.bottom = STATICHEIGHT;
391     cp->ypos += r.bottom + GAPWITHIN;
392     doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, text, id);
393     va_start(ap, id);
394     group = WS_GROUP;
395     while (1) {
396         char *btext;
397         int bid;
398         btext = va_arg(ap, char *);
399         if (!btext)
400             break;
401         bid = va_arg(ap, int);
402         r.left = GAPBETWEEN; r.top = cp->ypos;
403         r.right = cp->width; r.bottom = STATICHEIGHT;
404         cp->ypos += r.bottom + GAPWITHIN;
405         doctl(cp, r, "BUTTON",
406               BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP | group,
407               0,
408               btext, bid);
409         group = 0;
410     }
411     va_end(ap);
412     cp->ypos += GAPBETWEEN - GAPWITHIN;
413 }
414
415 /*
416  * A single standalone checkbox.
417  */
418 static void checkbox(struct ctlpos *cp, char *text, int id) {
419     RECT r;
420
421     r.left = GAPBETWEEN; r.top = cp->ypos;
422     r.right = cp->width; r.bottom = CHECKBOXHEIGHT;
423     cp->ypos += r.bottom + GAPBETWEEN;
424     doctl(cp, r, "BUTTON",
425           BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0,
426           text, id);
427 }
428
429 /*
430  * A button on the right hand side, with a static to its left.
431  */
432 static void staticbtn(struct ctlpos *cp, char *stext, int sid,
433                       char *btext, int bid) {
434     const int height = (PUSHBTNHEIGHT > STATICHEIGHT ?
435                         PUSHBTNHEIGHT : STATICHEIGHT);
436     RECT r;
437     int lwid, rwid, rpos;
438
439     rpos = GAPBETWEEN + 3 * (cp->width + GAPBETWEEN) / 4;
440     lwid = rpos - 2*GAPBETWEEN;
441     rwid = cp->width + GAPBETWEEN - rpos;
442
443     r.left = GAPBETWEEN; r.top = cp->ypos + (height-STATICHEIGHT)/2;
444     r.right = lwid; r.bottom = STATICHEIGHT;
445     doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
446
447     r.left = rpos; r.top = cp->ypos + (height-PUSHBTNHEIGHT)/2;
448     r.right = rwid; r.bottom = PUSHBTNHEIGHT;
449     doctl(cp, r, "BUTTON",
450           WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
451           0,
452           btext, bid);
453
454     cp->ypos += height + GAPBETWEEN;
455 }
456
457 /*
458  * An edit control on the right hand side, with a static to its left.
459  */
460 static void staticedit(struct ctlpos *cp, char *stext,
461                        int sid, int eid, int percentedit) {
462     const int height = (EDITHEIGHT > STATICHEIGHT ?
463                         EDITHEIGHT : STATICHEIGHT);
464     RECT r;
465     int lwid, rwid, rpos;
466
467     rpos = GAPBETWEEN + (100-percentedit) * (cp->width + GAPBETWEEN) / 100;
468     lwid = rpos - 2*GAPBETWEEN;
469     rwid = cp->width + GAPBETWEEN - rpos;
470
471     r.left = GAPBETWEEN; r.top = cp->ypos + (height-STATICHEIGHT)/2;
472     r.right = lwid; r.bottom = STATICHEIGHT;
473     doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
474
475     r.left = rpos; r.top = cp->ypos + (height-EDITHEIGHT)/2;
476     r.right = rwid; r.bottom = EDITHEIGHT;
477     doctl(cp, r, "EDIT",
478           WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
479           WS_EX_CLIENTEDGE,
480           "", eid);
481
482     cp->ypos += height + GAPBETWEEN;
483 }
484
485 /*
486  * A tab-control substitute when a real tab control is unavailable.
487  */
488 static void ersatztab(struct ctlpos *cp, char *stext, int sid,
489                       int lid, int s2id) {
490     const int height = (COMBOHEIGHT > STATICHEIGHT ?
491                         COMBOHEIGHT : STATICHEIGHT);
492     RECT r;
493     int bigwid, lwid, rwid, rpos;
494     static const int BIGGAP = 15;
495     static const int MEDGAP = 3;
496
497     bigwid = cp->width + 2*GAPBETWEEN - 2*BIGGAP;
498     cp->ypos += MEDGAP;
499     rpos = BIGGAP + (bigwid + BIGGAP) / 2;
500     lwid = rpos - 2*BIGGAP;
501     rwid = bigwid + BIGGAP - rpos;
502
503     r.left = BIGGAP; r.top = cp->ypos + (height-STATICHEIGHT)/2;
504     r.right = lwid; r.bottom = STATICHEIGHT;
505     doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
506
507     r.left = rpos; r.top = cp->ypos + (height-COMBOHEIGHT)/2;
508     r.right = rwid; r.bottom = COMBOHEIGHT*10;
509     doctl(cp, r, "COMBOBOX",
510           WS_CHILD | WS_VISIBLE | WS_TABSTOP |
511           CBS_DROPDOWNLIST | CBS_HASSTRINGS,
512           WS_EX_CLIENTEDGE,
513           "", lid);
514
515     cp->ypos += height + MEDGAP + GAPBETWEEN;
516
517     r.left = GAPBETWEEN; r.top = cp->ypos;
518     r.right = cp->width; r.bottom = 2;
519     doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE | SS_ETCHEDHORZ,
520           0, "", s2id);
521 }
522
523 /*
524  * A static line, followed by an edit control on the left hand side
525  * and a button on the right.
526  */
527 static void editbutton(struct ctlpos *cp, char *stext, int sid,
528                        int eid, char *btext, int bid) {
529     const int height = (EDITHEIGHT > PUSHBTNHEIGHT ?
530                         EDITHEIGHT : PUSHBTNHEIGHT);
531     RECT r;
532     int lwid, rwid, rpos;
533
534     r.left = GAPBETWEEN; r.top = cp->ypos;
535     r.right = cp->width; r.bottom = STATICHEIGHT;
536     cp->ypos += r.bottom + GAPWITHIN;
537     doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
538
539     rpos = GAPBETWEEN + 3 * (cp->width + GAPBETWEEN) / 4;
540     lwid = rpos - 2*GAPBETWEEN;
541     rwid = cp->width + GAPBETWEEN - rpos;
542
543     r.left = GAPBETWEEN; r.top = cp->ypos + (height-EDITHEIGHT)/2;
544     r.right = lwid; r.bottom = EDITHEIGHT;
545     doctl(cp, r, "EDIT",
546           WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
547           WS_EX_CLIENTEDGE,
548           "", eid);
549
550     r.left = rpos; r.top = cp->ypos + (height-PUSHBTNHEIGHT)/2;
551     r.right = rwid; r.bottom = PUSHBTNHEIGHT;
552     doctl(cp, r, "BUTTON",
553           WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
554           0,
555           btext, bid);
556
557     cp->ypos += height + GAPBETWEEN;
558 }
559
560 /*
561  * Special control which was hard to describe generically: the
562  * session-saver assembly. A static; below that an edit box; below
563  * that a list box. To the right of the list box, a column of
564  * buttons.
565  */
566 static void sesssaver(struct ctlpos *cp, char *text,
567                       int staticid, int editid, int listid, ...) {
568     RECT r;
569     va_list ap;
570     int lwid, rwid, rpos;
571     int y;
572     const int LISTDEFHEIGHT = 66;
573
574     rpos = GAPBETWEEN + 3 * (cp->width + GAPBETWEEN) / 4;
575     lwid = rpos - 2*GAPBETWEEN;
576     rwid = cp->width + GAPBETWEEN - rpos;
577
578     /* The static control. */
579     r.left = GAPBETWEEN; r.top = cp->ypos;
580     r.right = lwid; r.bottom = STATICHEIGHT;
581     cp->ypos += r.bottom + GAPWITHIN;
582     doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, text, staticid);
583
584     /* The edit control. */
585     r.left = GAPBETWEEN; r.top = cp->ypos;
586     r.right = lwid; r.bottom = EDITHEIGHT;
587     cp->ypos += r.bottom + GAPWITHIN;
588     doctl(cp, r, "EDIT",
589           WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
590           WS_EX_CLIENTEDGE,
591           "", editid);
592
593     /*
594      * The buttons (we should hold off on the list box until we
595      * know how big the buttons are).
596      */
597     va_start(ap, listid);
598     y = cp->ypos;
599     while (1) {
600         char *btext = va_arg(ap, char *);
601         int bid;
602         if (!btext) break;
603         bid = va_arg(ap, int);
604         r.left = rpos; r.top = y;
605         r.right = rwid; r.bottom = PUSHBTNHEIGHT;
606         y += r.bottom + GAPWITHIN;
607         doctl(cp, r, "BUTTON",
608               WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
609               0,
610               btext, bid);
611     }
612
613     /* Compute list box height. LISTDEFHEIGHT, or height of buttons. */
614     y -= cp->ypos;
615     y -= GAPWITHIN;
616     if (y < LISTDEFHEIGHT) y = LISTDEFHEIGHT;
617     r.left = GAPBETWEEN; r.top = cp->ypos;
618     r.right = lwid; r.bottom = y;
619     cp->ypos += y + GAPBETWEEN;
620     doctl(cp, r, "LISTBOX",
621           WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL | 
622           LBS_NOTIFY | LBS_HASSTRINGS,
623           WS_EX_CLIENTEDGE,
624           "", listid);
625 }
626
627 /*
628  * Another special control: the environment-variable setter. A
629  * static line first; then a pair of edit boxes with associated
630  * statics, and two buttons; then a list box.
631  */
632 static void envsetter(struct ctlpos *cp, char *stext, int sid,
633                       char *e1stext, int e1sid, int e1id,
634                       char *e2stext, int e2sid, int e2id,
635                       int listid,
636                       char *b1text, int b1id, char *b2text, int b2id) {
637     RECT r;
638     const int height = (STATICHEIGHT > EDITHEIGHT && STATICHEIGHT > PUSHBTNHEIGHT ?
639                         STATICHEIGHT :
640                         EDITHEIGHT > PUSHBTNHEIGHT ?
641                         EDITHEIGHT : PUSHBTNHEIGHT);
642     const static int percents[] = { 20, 35, 10, 25 };
643     int i, j, xpos, percent;
644     const int LISTHEIGHT = 42;
645
646     /* The static control. */
647     r.left = GAPBETWEEN; r.top = cp->ypos;
648     r.right = cp->width; r.bottom = STATICHEIGHT;
649     cp->ypos += r.bottom + GAPWITHIN;
650     doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
651
652     /* The statics+edits+buttons. */
653     for (j = 0; j < 2; j++) {
654         percent = 10;
655         for (i = 0; i < 4; i++) {
656             xpos = (cp->width + GAPBETWEEN) * percent / 100;
657             r.left = xpos + GAPBETWEEN;
658             percent += percents[i];
659             xpos = (cp->width + GAPBETWEEN) * percent / 100;
660             r.right = xpos - r.left;
661             r.top = cp->ypos;
662             r.bottom = (i==0 ? STATICHEIGHT :
663                         i==1 ? EDITHEIGHT :
664                         PUSHBTNHEIGHT);
665             r.top += (height-r.bottom)/2;
666             if (i==0) {
667                 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0,
668                       j==0 ? e1stext : e2stext, j==0 ? e1sid : e2sid);
669             } else if (i==1) {
670                 doctl(cp, r, "EDIT",
671                       WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
672                       WS_EX_CLIENTEDGE,
673                       "", j==0 ? e1id : e2id);
674             } else if (i==3) {
675                 doctl(cp, r, "BUTTON",
676                       WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
677                       0,
678                       j==0 ? b1text : b2text, j==0 ? b1id : b2id);
679             }
680         }
681         cp->ypos += height + GAPWITHIN;
682     }
683
684     /* The list box. */
685     r.left = GAPBETWEEN; r.top = cp->ypos;
686     r.right = cp->width; r.bottom = LISTHEIGHT;
687     cp->ypos += r.bottom + GAPBETWEEN;
688     doctl(cp, r, "LISTBOX",
689           WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL | LBS_HASSTRINGS |
690           LBS_USETABSTOPS,
691           WS_EX_CLIENTEDGE,
692           "", listid);
693 }
694
695 /*
696  * Yet another special control: the character-class setter. A
697  * static, then a list, then a line containing a
698  * button-and-static-and-edit. 
699  */
700 static void charclass(struct ctlpos *cp, char *stext, int sid, int listid,
701                       char *btext, int bid, int eid, char *s2text, int s2id) {
702     RECT r;
703     const int height = (STATICHEIGHT > EDITHEIGHT && STATICHEIGHT > PUSHBTNHEIGHT ?
704                         STATICHEIGHT :
705                         EDITHEIGHT > PUSHBTNHEIGHT ?
706                         EDITHEIGHT : PUSHBTNHEIGHT);
707     const static int percents[] = { 30, 40, 30 };
708     int i, xpos, percent;
709     const int LISTHEIGHT = 66;
710
711     /* The static control. */
712     r.left = GAPBETWEEN; r.top = cp->ypos;
713     r.right = cp->width; r.bottom = STATICHEIGHT;
714     cp->ypos += r.bottom + GAPWITHIN;
715     doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
716
717     /* The list box. */
718     r.left = GAPBETWEEN; r.top = cp->ypos;
719     r.right = cp->width; r.bottom = LISTHEIGHT;
720     cp->ypos += r.bottom + GAPWITHIN;
721     doctl(cp, r, "LISTBOX",
722           WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL | LBS_HASSTRINGS |
723           LBS_USETABSTOPS,
724           WS_EX_CLIENTEDGE,
725           "", listid);
726
727     /* The button+static+edit. */
728     percent = xpos = 0;
729     for (i = 0; i < 3; i++) {
730         r.left = xpos + GAPBETWEEN;
731         percent += percents[i];
732         xpos = (cp->width + GAPBETWEEN) * percent / 100;
733         r.right = xpos - r.left;
734         r.top = cp->ypos;
735         r.bottom = (i==0 ? PUSHBTNHEIGHT :
736                     i==1 ? STATICHEIGHT :
737                     EDITHEIGHT);
738         r.top += (height-r.bottom)/2;
739         if (i==0) {
740             doctl(cp, r, "BUTTON",
741                   WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
742                   0, btext, bid);
743         } else if (i==1) {
744             doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE | SS_CENTER,
745                   0, s2text, s2id);
746         } else if (i==2) {
747             doctl(cp, r, "EDIT",
748                   WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
749                   WS_EX_CLIENTEDGE, "", eid);
750         }
751     }
752     cp->ypos += height + GAPBETWEEN;
753 }
754
755 /*
756  * A special control (horrors!). The colour editor. A static line;
757  * then on the left, a list box, and on the right, a sequence of
758  * two-part statics followed by a button.
759  */
760 static void colouredit(struct ctlpos *cp, char *stext, int sid, int listid,
761                        char *btext, int bid, ...) {
762     RECT r;
763     int y;
764     va_list ap;
765     int lwid, rwid, rpos;
766     const int LISTHEIGHT = 66;
767
768     /* The static control. */
769     r.left = GAPBETWEEN; r.top = cp->ypos;
770     r.right = cp->width; r.bottom = STATICHEIGHT;
771     cp->ypos += r.bottom + GAPWITHIN;
772     doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
773     
774     rpos = GAPBETWEEN + 2 * (cp->width + GAPBETWEEN) / 3;
775     lwid = rpos - 2*GAPBETWEEN;
776     rwid = cp->width + GAPBETWEEN - rpos;
777
778     /* The list box. */
779     r.left = GAPBETWEEN; r.top = cp->ypos;
780     r.right = lwid; r.bottom = LISTHEIGHT;
781     doctl(cp, r, "LISTBOX",
782           WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL | LBS_HASSTRINGS |
783           LBS_USETABSTOPS,
784           WS_EX_CLIENTEDGE,
785           "", listid);
786
787     /* The statics. */
788     y = cp->ypos;
789     va_start(ap, bid);
790     while (1) {
791         char *ltext;
792         int lid, rid;
793         ltext = va_arg(ap, char *);
794         if (!ltext) break;
795         lid = va_arg(ap, int);
796         rid = va_arg(ap, int);
797         r.top = y; r.bottom = STATICHEIGHT;
798         y += r.bottom + GAPWITHIN;
799         r.left = rpos; r.right = rwid/2;
800         doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, ltext, lid);
801         r.left = rpos + r.right; r.right = rwid - r.right;
802         doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE | SS_RIGHT, 0, "", rid);
803     }
804     va_end(ap);
805
806     /* The button. */
807     r.top = y + 2*GAPWITHIN; r.bottom = PUSHBTNHEIGHT;
808     r.left = rpos; r.right = rwid;
809     doctl(cp, r, "BUTTON",
810           WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
811           0, btext, bid);
812
813     cp->ypos += LISTHEIGHT + GAPBETWEEN;
814 }
815
816 static char savedsession[2048];
817
818 enum { IDCX_ABOUT = IDC_ABOUT, IDCX_TVSTATIC, IDCX_TREEVIEW, controlstartvalue,
819
820     sessionpanelstart,
821     IDC_TITLE_SESSION,
822     IDC_BOX_SESSION1, IDC_BOXT_SESSION1,
823     IDC_BOX_SESSION2, IDC_BOXT_SESSION2,
824     IDC_BOX_SESSION3,
825     IDC_HOSTSTATIC,
826     IDC_HOST,
827     IDC_PORTSTATIC,
828     IDC_PORT,
829     IDC_PROTSTATIC,
830     IDC_PROTRAW,
831     IDC_PROTTELNET,
832     IDC_PROTSSH,
833     IDC_SESSSTATIC,
834     IDC_SESSEDIT,
835     IDC_SESSLIST,
836     IDC_SESSLOAD,
837     IDC_SESSSAVE,
838     IDC_SESSDEL,
839     IDC_CLOSEEXIT,
840     sessionpanelend,
841
842     keyboardpanelstart,
843     IDC_TITLE_KEYBOARD,
844     IDC_BOX_KEYBOARD1, IDC_BOXT_KEYBOARD1,
845     IDC_BOX_KEYBOARD2, IDC_BOXT_KEYBOARD2,
846     IDC_DELSTATIC,
847     IDC_DEL008,
848     IDC_DEL127,
849     IDC_HOMESTATIC,
850     IDC_HOMETILDE,
851     IDC_HOMERXVT,
852     IDC_FUNCSTATIC,
853     IDC_FUNCTILDE,
854     IDC_FUNCLINUX,
855     IDC_FUNCXTERM,
856     IDC_FUNCVT400,
857     IDC_KPSTATIC,
858     IDC_KPNORMAL,
859     IDC_KPAPPLIC,
860     IDC_KPNH,
861     IDC_CURSTATIC,
862     IDC_CURNORMAL,
863     IDC_CURAPPLIC,
864     keyboardpanelend,
865
866     terminalpanelstart,
867     IDC_TITLE_TERMINAL,
868     IDC_BOX_TERMINAL1, IDC_BOXT_TERMINAL1,
869     IDC_BOX_TERMINAL2, IDC_BOXT_TERMINAL2,
870     IDC_BOX_TERMINAL3, IDC_BOXT_TERMINAL3,
871     IDC_WRAPMODE,
872     IDC_DECOM,
873     IDC_DIMSTATIC,
874     IDC_ROWSSTATIC,
875     IDC_ROWSEDIT,
876     IDC_COLSSTATIC,
877     IDC_COLSEDIT,
878     IDC_LOCKSIZE,
879     IDC_FONTSTATIC,
880     IDC_CHOOSEFONT,
881     IDC_LFHASCR,
882     IDC_BEEP,
883     IDC_BCE,
884     IDC_BLINKTEXT,
885     IDC_LDISCTERM,
886     terminalpanelend,
887
888     windowpanelstart,
889     IDC_TITLE_WINDOW,
890     IDC_BOX_WINDOW1, IDC_BOXT_WINDOW1,
891     IDC_BOX_WINDOW2, IDC_BOXT_WINDOW2,
892     IDC_BOX_WINDOW3, IDC_BOXT_WINDOW3,
893     IDC_BOX_WINDOW4,
894     IDC_WINNAME,
895     IDC_BLINKCUR,
896     IDC_SCROLLBAR,
897     IDC_WINTITLE,
898     IDC_WINEDIT,
899     IDC_CLOSEWARN,
900     IDC_SAVESTATIC,
901     IDC_SAVEEDIT,
902     IDC_ALTF4,
903     IDC_ALTSPACE,
904     IDC_SCROLLKEY,
905     windowpanelend,
906
907     connectionpanelstart,
908     IDC_TITLE_CONNECTION,
909     IDC_BOX_CONNECTION1, IDC_BOXT_CONNECTION1,
910     IDC_BOX_CONNECTION2, IDC_BOXT_CONNECTION2,
911     IDC_TTSTATIC,
912     IDC_TTEDIT,
913     IDC_LOGSTATIC,
914     IDC_LOGEDIT,
915     IDC_PINGSTATIC,
916     IDC_PINGEDIT,
917     connectionpanelend,
918
919     telnetpanelstart,
920     IDC_TITLE_TELNET,
921     IDC_BOX_TELNET1, IDC_BOXT_TELNET1,
922     IDC_BOX_TELNET2, IDC_BOXT_TELNET2,
923     IDC_TSSTATIC,
924     IDC_TSEDIT,
925     IDC_ENVSTATIC,
926     IDC_VARSTATIC,
927     IDC_VAREDIT,
928     IDC_VALSTATIC,
929     IDC_VALEDIT,
930     IDC_ENVLIST,
931     IDC_ENVADD,
932     IDC_ENVREMOVE,
933     IDC_EMSTATIC,
934     IDC_EMBSD,
935     IDC_EMRFC,
936     telnetpanelend,
937
938     sshpanelstart,
939     IDC_TITLE_SSH,
940     IDC_BOX_SSH1, IDC_BOXT_SSH1,
941     IDC_BOX_SSH2, IDC_BOXT_SSH2,
942     IDC_BOX_SSH3, IDC_BOXT_SSH3,
943     IDC_NOPTY,
944     IDC_CIPHERSTATIC,
945     IDC_CIPHER3DES,
946     IDC_CIPHERBLOWF,
947     IDC_CIPHERDES,
948     IDC_AUTHTIS,
949     IDC_PKSTATIC,
950     IDC_PKEDIT,
951     IDC_PKBUTTON,
952     IDC_SSHPROTSTATIC,
953     IDC_SSHPROT1,
954     IDC_SSHPROT2,
955     IDC_AGENTFWD,
956     IDC_CMDSTATIC,
957     IDC_CMDEDIT,
958     sshpanelend,
959
960     selectionpanelstart,
961     IDC_TITLE_SELECTION,
962     IDC_BOX_SELECTION1, IDC_BOXT_SELECTION1,
963     IDC_BOX_SELECTION2, IDC_BOXT_SELECTION2,
964     IDC_MBSTATIC,
965     IDC_MBWINDOWS,
966     IDC_MBXTERM,
967     IDC_CCSTATIC,
968     IDC_CCLIST,
969     IDC_CCSET,
970     IDC_CCSTATIC2,
971     IDC_CCEDIT,
972     selectionpanelend,
973
974     colourspanelstart,
975     IDC_TITLE_COLOURS,
976     IDC_BOX_COLOURS1, IDC_BOXT_COLOURS1,
977     IDC_BOX_COLOURS2, IDC_BOXT_COLOURS2,
978     IDC_BOLDCOLOUR,
979     IDC_PALETTE,
980     IDC_STATIC,
981     IDC_LIST,
982     IDC_RSTATIC,
983     IDC_GSTATIC,
984     IDC_BSTATIC,
985     IDC_RVALUE,
986     IDC_GVALUE,
987     IDC_BVALUE,
988     IDC_CHANGE,
989     colourspanelend,
990
991     translationpanelstart,
992     IDC_TITLE_TRANSLATION,
993     IDC_BOX_TRANSLATION1, IDC_BOXT_TRANSLATION1,
994     IDC_BOX_TRANSLATION2, IDC_BOXT_TRANSLATION2,
995     IDC_BOX_TRANSLATION3, IDC_BOXT_TRANSLATION3,
996     IDC_XLATSTATIC,
997     IDC_NOXLAT,
998     IDC_KOI8WIN1251,
999     IDC_88592WIN1250,
1000     IDC_88592CP852,
1001     IDC_CAPSLOCKCYR,
1002     IDC_VTSTATIC,
1003     IDC_VTXWINDOWS,
1004     IDC_VTOEMANSI,
1005     IDC_VTOEMONLY,
1006     IDC_VTPOORMAN,
1007     translationpanelend,
1008
1009     controlendvalue
1010 };
1011
1012 static const char *const colours[] = {
1013     "Default Foreground", "Default Bold Foreground",
1014     "Default Background", "Default Bold Background",
1015     "Cursor Text", "Cursor Colour",
1016     "ANSI Black", "ANSI Black Bold",
1017     "ANSI Red", "ANSI Red Bold",
1018     "ANSI Green", "ANSI Green Bold",
1019     "ANSI Yellow", "ANSI Yellow Bold",
1020     "ANSI Blue", "ANSI Blue Bold",
1021     "ANSI Magenta", "ANSI Magenta Bold",
1022     "ANSI Cyan", "ANSI Cyan Bold",
1023     "ANSI White", "ANSI White Bold"
1024 };
1025 static const int permcolour[] = {
1026     TRUE, FALSE, TRUE, FALSE, TRUE, TRUE,
1027     TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE,
1028     TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE
1029 };
1030
1031 static void fmtfont (char *buf) {
1032     sprintf (buf, "Font: %s, ", cfg.font);
1033     if (cfg.fontisbold)
1034         strcat(buf, "bold, ");
1035     if (cfg.fontheight == 0)
1036         strcat (buf, "default height");
1037     else
1038         sprintf (buf+strlen(buf), "%d-%s",
1039                  (cfg.fontheight < 0 ? -cfg.fontheight : cfg.fontheight),
1040                  (cfg.fontheight < 0 ? "pixel" : "point"));
1041 }
1042
1043 static void init_dlg_ctrls(HWND hwnd) {
1044     int i;
1045     char fontstatic[256];
1046
1047     SetDlgItemText (hwnd, IDC_HOST, cfg.host);
1048     SetDlgItemText (hwnd, IDC_SESSEDIT, savedsession);
1049     SetDlgItemInt (hwnd, IDC_PORT, cfg.port, FALSE);
1050     for (i = 0; i < nsessions; i++)
1051         SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_ADDSTRING,
1052                             0, (LPARAM) (sessions[i]));
1053     CheckRadioButton (hwnd, IDC_PROTRAW, IDC_PROTSSH,
1054                       cfg.protocol==PROT_SSH ? IDC_PROTSSH :
1055                       cfg.protocol==PROT_TELNET ? IDC_PROTTELNET : IDC_PROTRAW );
1056     SetDlgItemInt (hwnd, IDC_PINGEDIT, cfg.ping_interval, FALSE);
1057
1058     CheckRadioButton (hwnd, IDC_DEL008, IDC_DEL127,
1059                       cfg.bksp_is_delete ? IDC_DEL127 : IDC_DEL008);
1060     CheckRadioButton (hwnd, IDC_HOMETILDE, IDC_HOMERXVT,
1061                       cfg.rxvt_homeend ? IDC_HOMERXVT : IDC_HOMETILDE);
1062     CheckRadioButton (hwnd, IDC_FUNCTILDE, IDC_FUNCXTERM,
1063                       cfg.funky_type == 0 ? IDC_FUNCTILDE :
1064                       cfg.funky_type == 1 ? IDC_FUNCLINUX :
1065                       cfg.funky_type == 2 ? IDC_FUNCXTERM :
1066                       cfg.funky_type == 3 ? IDC_FUNCVT400 :
1067                       IDC_FUNCTILDE );
1068     CheckRadioButton (hwnd, IDC_CURNORMAL, IDC_CURAPPLIC,
1069                       cfg.app_cursor ? IDC_CURAPPLIC : IDC_CURNORMAL);
1070     CheckRadioButton (hwnd, IDC_KPNORMAL, IDC_KPNH,
1071                       cfg.nethack_keypad ? IDC_KPNH :
1072                       cfg.app_keypad ? IDC_KPAPPLIC : IDC_KPNORMAL);
1073     CheckDlgButton (hwnd, IDC_ALTF4, cfg.alt_f4);
1074     CheckDlgButton (hwnd, IDC_ALTSPACE, cfg.alt_space);
1075     CheckDlgButton (hwnd, IDC_LDISCTERM, cfg.ldisc_term);
1076     CheckDlgButton (hwnd, IDC_SCROLLKEY, cfg.scroll_on_key);
1077
1078     CheckDlgButton (hwnd, IDC_WRAPMODE, cfg.wrap_mode);
1079     CheckDlgButton (hwnd, IDC_DECOM, cfg.dec_om);
1080     CheckDlgButton (hwnd, IDC_LFHASCR, cfg.lfhascr);
1081     SetDlgItemInt (hwnd, IDC_ROWSEDIT, cfg.height, FALSE);
1082     SetDlgItemInt (hwnd, IDC_COLSEDIT, cfg.width, FALSE);
1083     SetDlgItemInt (hwnd, IDC_SAVEEDIT, cfg.savelines, FALSE);
1084     fmtfont (fontstatic);
1085     SetDlgItemText (hwnd, IDC_FONTSTATIC, fontstatic);
1086     CheckDlgButton (hwnd, IDC_BEEP, cfg.beep);
1087     CheckDlgButton (hwnd, IDC_BCE, cfg.bce);
1088     CheckDlgButton (hwnd, IDC_BLINKTEXT, cfg.blinktext);
1089
1090     SetDlgItemText (hwnd, IDC_WINEDIT, cfg.wintitle);
1091     CheckDlgButton (hwnd, IDC_WINNAME, cfg.win_name_always);
1092     CheckDlgButton (hwnd, IDC_BLINKCUR, cfg.blink_cur);
1093     CheckDlgButton (hwnd, IDC_SCROLLBAR, cfg.scrollbar);
1094     CheckDlgButton (hwnd, IDC_LOCKSIZE, cfg.locksize);
1095     CheckDlgButton (hwnd, IDC_CLOSEEXIT, cfg.close_on_exit);
1096     CheckDlgButton (hwnd, IDC_CLOSEWARN, cfg.warn_on_close);
1097
1098     SetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype);
1099     SetDlgItemText (hwnd, IDC_TSEDIT, cfg.termspeed);
1100     SetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username);
1101     {
1102         char *p = cfg.environmt;
1103         while (*p) {
1104             SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_ADDSTRING, 0,
1105                                 (LPARAM) p);
1106             p += strlen(p)+1;
1107         }
1108     }
1109     CheckRadioButton (hwnd, IDC_EMBSD, IDC_EMRFC,
1110                       cfg.rfc_environ ? IDC_EMRFC : IDC_EMBSD);
1111
1112     SetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype);
1113     SetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username);
1114     CheckDlgButton (hwnd, IDC_NOPTY, cfg.nopty);
1115     CheckDlgButton (hwnd, IDC_AGENTFWD, cfg.agentfwd);
1116     CheckRadioButton (hwnd, IDC_CIPHER3DES, IDC_CIPHERDES,
1117                       cfg.cipher == CIPHER_BLOWFISH ? IDC_CIPHERBLOWF :
1118                       cfg.cipher == CIPHER_DES ? IDC_CIPHERDES :
1119                       IDC_CIPHER3DES);
1120     CheckRadioButton (hwnd, IDC_SSHPROT1, IDC_SSHPROT2,
1121                       cfg.sshprot == 1 ? IDC_SSHPROT1 : IDC_SSHPROT2);
1122     CheckDlgButton (hwnd, IDC_AUTHTIS, cfg.try_tis_auth);
1123     SetDlgItemText (hwnd, IDC_PKEDIT, cfg.keyfile);
1124     SetDlgItemText (hwnd, IDC_CMDEDIT, cfg.remote_cmd);
1125
1126     CheckRadioButton (hwnd, IDC_MBWINDOWS, IDC_MBXTERM,
1127                       cfg.mouse_is_xterm ? IDC_MBXTERM : IDC_MBWINDOWS);
1128     {
1129         static int tabs[4] = {25, 61, 96, 128};
1130         SendDlgItemMessage (hwnd, IDC_CCLIST, LB_SETTABSTOPS, 4,
1131                             (LPARAM) tabs);
1132     }
1133     for (i=0; i<256; i++) {
1134         char str[100];
1135         sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
1136                 (i>=0x21 && i != 0x7F) ? i : ' ',
1137                 cfg.wordness[i]);
1138         SendDlgItemMessage (hwnd, IDC_CCLIST, LB_ADDSTRING, 0,
1139                             (LPARAM) str);
1140     }
1141
1142     CheckDlgButton (hwnd, IDC_BOLDCOLOUR, cfg.bold_colour);
1143     CheckDlgButton (hwnd, IDC_PALETTE, cfg.try_palette);
1144     {
1145         int i;
1146         for (i=0; i<22; i++)
1147             if (cfg.bold_colour || permcolour[i])
1148                 SendDlgItemMessage (hwnd, IDC_LIST, LB_ADDSTRING, 0,
1149                                     (LPARAM) colours[i]);
1150     }
1151     SendDlgItemMessage (hwnd, IDC_LIST, LB_SETCURSEL, 0, 0);
1152     SetDlgItemInt (hwnd, IDC_RVALUE, cfg.colours[0][0], FALSE);
1153     SetDlgItemInt (hwnd, IDC_GVALUE, cfg.colours[0][1], FALSE);
1154     SetDlgItemInt (hwnd, IDC_BVALUE, cfg.colours[0][2], FALSE);
1155
1156     CheckRadioButton (hwnd, IDC_NOXLAT, IDC_88592CP852,
1157                       cfg.xlat_88592w1250 ? IDC_88592WIN1250 :
1158                       cfg.xlat_88592cp852 ? IDC_88592CP852 :
1159                       cfg.xlat_enablekoiwin ? IDC_KOI8WIN1251 :
1160                       IDC_NOXLAT);
1161     CheckDlgButton (hwnd, IDC_CAPSLOCKCYR, cfg.xlat_capslockcyr);
1162     CheckRadioButton (hwnd, IDC_VTXWINDOWS, IDC_VTPOORMAN,
1163                       cfg.vtmode == VT_XWINDOWS ? IDC_VTXWINDOWS :
1164                       cfg.vtmode == VT_OEMANSI ? IDC_VTOEMANSI :
1165                       cfg.vtmode == VT_OEMONLY ? IDC_VTOEMONLY :
1166                       IDC_VTPOORMAN);
1167 }
1168
1169 static void hide(HWND hwnd, int hide, int minid, int maxid) {
1170     int i;
1171     for (i = minid; i < maxid; i++) {
1172         HWND ctl = GetDlgItem(hwnd, i);
1173         if (ctl) {
1174             ShowWindow(ctl, hide ? SW_HIDE : SW_SHOW);
1175         }
1176     }
1177 }
1178
1179 struct treeview_faff {
1180     HWND treeview;
1181     HTREEITEM lastat[4];
1182 };
1183
1184 static HTREEITEM treeview_insert(struct treeview_faff *faff,
1185                                  int level, char *text) {
1186     TVINSERTSTRUCT ins;
1187     int i;
1188     HTREEITEM newitem;
1189     ins.hParent = (level > 0 ? faff->lastat[level-1] : TVI_ROOT);
1190     ins.hInsertAfter = faff->lastat[level];
1191 #if _WIN32_IE >= 0x0400 && defined NONAMELESSUNION
1192 #define INSITEM DUMMYUNIONNAME.item
1193 #else
1194 #define INSITEM item
1195 #endif
1196     ins.INSITEM.mask = TVIF_TEXT;
1197     ins.INSITEM.pszText = text;
1198     newitem = TreeView_InsertItem(faff->treeview, &ins);
1199     if (level > 0)
1200         TreeView_Expand(faff->treeview, faff->lastat[level-1], TVE_EXPAND);
1201     faff->lastat[level] = newitem;
1202     for (i = level+1; i < 4; i++) faff->lastat[i] = NULL;
1203     return newitem;
1204 }
1205
1206 /*
1207  * This _huge_ function is the configuration box.
1208  */
1209 static int GenericMainDlgProc (HWND hwnd, UINT msg,
1210                                WPARAM wParam, LPARAM lParam,
1211                                int dlgtype) {
1212     HWND hw, treeview;
1213     struct treeview_faff tvfaff;
1214     HTREEITEM hsession;
1215     OPENFILENAME of;
1216     char filename[sizeof(cfg.keyfile)];
1217     CHOOSEFONT cf;
1218     LOGFONT lf;
1219     char fontstatic[256];
1220     int i;
1221
1222     switch (msg) {
1223       case WM_INITDIALOG:
1224         SetWindowLong(hwnd, GWL_USERDATA, 0);
1225         /*
1226          * Centre the window.
1227          */
1228         {                              /* centre the window */
1229             RECT rs, rd;
1230
1231             hw = GetDesktopWindow();
1232             if (GetWindowRect (hw, &rs) && GetWindowRect (hwnd, &rd))
1233                 MoveWindow (hwnd, (rs.right + rs.left + rd.left - rd.right)/2,
1234                             (rs.bottom + rs.top + rd.top - rd.bottom)/2,
1235                             rd.right-rd.left, rd.bottom-rd.top, TRUE);
1236         }
1237
1238         /*
1239          * Create the tree view.
1240          */
1241         {
1242             RECT r;
1243             WPARAM font;
1244             HWND tvstatic;
1245
1246             r.left = 3; r.right = r.left + 75;
1247             r.top = 3; r.bottom = r.top + 10;
1248             MapDialogRect(hwnd, &r);
1249             tvstatic = CreateWindowEx(0, "STATIC", "Cate&gory:",
1250                                       WS_CHILD | WS_VISIBLE,
1251                                       r.left, r.top,
1252                                       r.right-r.left, r.bottom-r.top,
1253                                       hwnd, (HMENU)IDCX_TVSTATIC, hinst, NULL);
1254             font = SendMessage(hwnd, WM_GETFONT, 0, 0);
1255             SendMessage(tvstatic, WM_SETFONT, font, MAKELPARAM(TRUE, 0));
1256
1257             r.left = 3; r.right = r.left + 75;
1258             r.top = 13; r.bottom = r.top + 196;
1259             MapDialogRect(hwnd, &r);
1260             treeview = CreateWindowEx(WS_EX_CLIENTEDGE, WC_TREEVIEW, "",
1261                                       WS_CHILD | WS_VISIBLE |
1262                                       WS_TABSTOP | TVS_HASLINES |
1263                                       TVS_DISABLEDRAGDROP | TVS_HASBUTTONS |
1264                                       TVS_LINESATROOT | TVS_SHOWSELALWAYS,
1265                                       r.left, r.top,
1266                                       r.right-r.left, r.bottom-r.top,
1267                                       hwnd, (HMENU)IDCX_TREEVIEW, hinst, NULL);
1268             font = SendMessage(hwnd, WM_GETFONT, 0, 0);
1269             SendMessage(treeview, WM_SETFONT, font, MAKELPARAM(TRUE, 0));
1270             tvfaff.treeview = treeview;
1271             memset(tvfaff.lastat, 0, sizeof(tvfaff.lastat));
1272         }
1273
1274         /*
1275          * Create the various panelfuls of controls.
1276          */
1277
1278         /* The Session panel. Accelerators used: [acgo] nprthelsdx */
1279         {
1280             struct ctlpos cp;
1281             ctlposinit(&cp, hwnd, 80, 3, 13);
1282             bartitle(&cp, "Basic options for your PuTTY session",
1283                      IDC_TITLE_SESSION);
1284             if (dlgtype == 0) {
1285                 beginbox(&cp, "Specify your connection by host name",
1286                          IDC_BOX_SESSION1, IDC_BOXT_SESSION1);
1287                 multiedit(&cp,
1288                           "Host &Name", IDC_HOSTSTATIC, IDC_HOST, 75,
1289                           "&Port", IDC_PORTSTATIC, IDC_PORT, 25, NULL);
1290                 if (backends[2].backend == NULL) {
1291                     /* this is PuTTYtel, so only two protocols available */
1292                     radioline(&cp, "Protocol:", IDC_PROTSTATIC, 3,
1293                               "&Raw", IDC_PROTRAW,
1294                               "&Telnet", IDC_PROTTELNET, NULL);
1295                 } else {
1296                     radioline(&cp, "Protocol:", IDC_PROTSTATIC, 3,
1297                               "&Raw", IDC_PROTRAW,
1298                               "&Telnet", IDC_PROTTELNET,
1299 #ifdef FWHACK
1300                               "SS&H/hack",
1301 #else
1302                               "SS&H",
1303 #endif
1304                               IDC_PROTSSH, NULL);
1305                 }
1306                 endbox(&cp);
1307                 beginbox(&cp, "Load, save or delete a stored session",
1308                          IDC_BOX_SESSION2, IDC_BOXT_SESSION2);
1309                 sesssaver(&cp, "Stor&ed Sessions",
1310                           IDC_SESSSTATIC, IDC_SESSEDIT, IDC_SESSLIST,
1311                           "&Load", IDC_SESSLOAD,
1312                           "&Save", IDC_SESSSAVE,
1313                           "&Delete", IDC_SESSDEL, NULL);
1314                 endbox(&cp);
1315             }
1316             beginbox(&cp, NULL, IDC_BOX_SESSION3, 0);
1317             checkbox(&cp, "Close Window on E&xit", IDC_CLOSEEXIT);
1318             endbox(&cp);
1319
1320             hsession = treeview_insert(&tvfaff, 0, "Session");
1321         }
1322
1323         /* The Terminal panel. Accelerators used: [acgo] rmkh&dlbenu */
1324         {
1325             struct ctlpos cp;
1326             ctlposinit(&cp, hwnd, 80, 3, 13);
1327             bartitle(&cp, "Options controlling the terminal emulation",
1328                      IDC_TITLE_TERMINAL);
1329             beginbox(&cp, "Set the size of the terminal window",
1330                      IDC_BOX_TERMINAL1, IDC_BOXT_TERMINAL1);
1331             multiedit(&cp,
1332                       "&Rows", IDC_ROWSSTATIC, IDC_ROWSEDIT, 50,
1333                       "Colu&mns", IDC_COLSSTATIC, IDC_COLSEDIT, 50,
1334                       NULL);
1335             checkbox(&cp, "Loc&k window size against resizing", IDC_LOCKSIZE);
1336             endbox(&cp);
1337             beginbox(&cp, "Set the font used in the terminal window",
1338                      IDC_BOX_TERMINAL2, IDC_BOXT_TERMINAL2);
1339             staticbtn(&cp, "", IDC_FONTSTATIC, "C&hange...", IDC_CHOOSEFONT);
1340             endbox(&cp);
1341             beginbox(&cp, "Set various terminal options",
1342                      IDC_BOX_TERMINAL3, IDC_BOXT_TERMINAL3);
1343             checkbox(&cp, "Auto &wrap mode initially on", IDC_WRAPMODE);
1344             checkbox(&cp, "&DEC Origin Mode initially on", IDC_DECOM);
1345             checkbox(&cp, "Implicit CR in every &LF", IDC_LFHASCR);
1346             checkbox(&cp, "&Beep enabled", IDC_BEEP);
1347             checkbox(&cp, "Use background colour to &erase screen", IDC_BCE);
1348             checkbox(&cp, "Enable bli&nking text", IDC_BLINKTEXT);
1349             checkbox(&cp, "&Use local terminal line discipline", IDC_LDISCTERM);
1350             endbox(&cp);
1351
1352             treeview_insert(&tvfaff, 0, "Terminal");
1353         }
1354
1355         /* The Keyboard panel. Accelerators used: [acgo] h?srvlxvnpmie */
1356         {
1357             struct ctlpos cp;
1358             ctlposinit(&cp, hwnd, 80, 3, 13);
1359             bartitle(&cp, "Options controlling the effects of keys",
1360                      IDC_TITLE_KEYBOARD);
1361             beginbox(&cp, "Change the sequences sent by:",
1362                      IDC_BOX_KEYBOARD1, IDC_BOXT_KEYBOARD1);
1363             radioline(&cp, "The Backspace key", IDC_DELSTATIC, 2,
1364                       "Control-&H", IDC_DEL008,
1365                       "Control-&? (127)", IDC_DEL127, NULL);
1366             radioline(&cp, "The Home and End keys", IDC_HOMESTATIC, 2,
1367                       "&Standard", IDC_HOMETILDE,
1368                       "&rxvt", IDC_HOMERXVT, NULL);
1369             radioline(&cp, "The Function keys and keypad", IDC_FUNCSTATIC, 4,
1370                       "&VT400", IDC_FUNCTILDE,
1371                       "&Linux", IDC_FUNCLINUX,
1372                       "&Xterm R6", IDC_FUNCXTERM,
1373                       "&VT400", IDC_FUNCVT400, NULL);
1374             endbox(&cp);
1375             beginbox(&cp, "Change the initial state of:",
1376                      IDC_BOX_KEYBOARD2, IDC_BOXT_KEYBOARD2);
1377             radioline(&cp, "Initial state of cursor keys:", IDC_CURSTATIC, 2,
1378                       "&Normal", IDC_CURNORMAL,
1379                       "A&pplication", IDC_CURAPPLIC, NULL);
1380             radioline(&cp, "Initial state of numeric keypad:", IDC_KPSTATIC, 3,
1381                       "Nor&mal", IDC_KPNORMAL,
1382                       "Appl&ication", IDC_KPAPPLIC,
1383                       "N&etHack", IDC_KPNH, NULL);
1384             endbox(&cp);
1385
1386             treeview_insert(&tvfaff, 1, "Keyboard");
1387         }
1388
1389         /* The Window panel. Accelerators used: [acgo] tibsdkw4y */
1390         {
1391             struct ctlpos cp;
1392             ctlposinit(&cp, hwnd, 80, 3, 13);
1393             bartitle(&cp, "Options controlling PuTTY's window",
1394                      IDC_TITLE_WINDOW);
1395             beginbox(&cp, "Adjust the use of the window title",
1396                      IDC_BOX_WINDOW1, IDC_BOXT_WINDOW1);
1397             if (dlgtype == 0)
1398                 multiedit(&cp,
1399                           "Initial window &title:", IDC_WINTITLE,
1400                           IDC_WINEDIT, 100, NULL);
1401             checkbox(&cp, "Avoid ever using &icon title", IDC_WINNAME);
1402             endbox(&cp);
1403             beginbox(&cp, "Adjust the use of the cursor",
1404                      IDC_BOX_WINDOW2, IDC_BOXT_WINDOW2);
1405             checkbox(&cp, "Cursor &blinks", IDC_BLINKCUR);
1406             endbox(&cp);
1407             beginbox(&cp, "Control the scrollback in the window",
1408                      IDC_BOX_WINDOW3, IDC_BOXT_WINDOW3);
1409             staticedit(&cp, "Lines of &scrollback",
1410                        IDC_SAVESTATIC, IDC_SAVEEDIT, 50);
1411             checkbox(&cp, "&Display scrollbar", IDC_SCROLLBAR);
1412             checkbox(&cp, "Reset scrollback on &keypress", IDC_SCROLLKEY);
1413             endbox(&cp);
1414             beginbox(&cp, NULL, IDC_BOX_WINDOW4, 0);
1415             checkbox(&cp, "&Warn before closing window", IDC_CLOSEWARN);
1416             checkbox(&cp, "Window closes on ALT-F&4", IDC_ALTF4);
1417             checkbox(&cp, "S&ystem menu appears on ALT-Space)", IDC_ALTSPACE);
1418             endbox(&cp);
1419
1420             treeview_insert(&tvfaff, 0, "Window");
1421         }
1422
1423         /* The Translation panel. Accelerators used: [acgo] xbepnkis */
1424         {
1425             struct ctlpos cp;
1426             ctlposinit(&cp, hwnd, 80, 3, 13);
1427             bartitle(&cp, "Options controlling character set translation",
1428                      IDC_TITLE_TRANSLATION);
1429             beginbox(&cp, "Adjust how PuTTY displays line drawing characters",
1430                      IDC_BOX_TRANSLATION1, IDC_BOXT_TRANSLATION1);
1431             radiobig(&cp,
1432                      "Handling of line drawing characters:", IDC_VTSTATIC,
1433                      "Font has &XWindows encoding", IDC_VTXWINDOWS,
1434                      "Use font in &both ANSI and OEM modes", IDC_VTOEMANSI,
1435                      "Use font in O&EM mode only", IDC_VTOEMONLY,
1436                      "&Poor man's line drawing (""+"", ""-"" and ""|"")",
1437                      IDC_VTPOORMAN, NULL);
1438             endbox(&cp);
1439             beginbox(&cp, "Enable character set translation on received data",
1440                      IDC_BOX_TRANSLATION2, IDC_BOXT_TRANSLATION2);
1441             radiobig(&cp,
1442                      "Character set translation:", IDC_XLATSTATIC,
1443                      "&None", IDC_NOXLAT,
1444                      "&KOI8 / Win-1251", IDC_KOI8WIN1251,
1445                      "&ISO-8859-2 / Win-1250", IDC_88592WIN1250,
1446                      "&ISO-8859-2 / CP852", IDC_88592CP852, NULL);
1447             endbox(&cp);
1448             beginbox(&cp, "Enable character set translation on input data",
1449                      IDC_BOX_TRANSLATION3, IDC_BOXT_TRANSLATION3);
1450             checkbox(&cp, "CAP&S LOCK acts as cyrillic switch",
1451                      IDC_CAPSLOCKCYR);
1452             endbox(&cp);
1453
1454             treeview_insert(&tvfaff, 1, "Translation");
1455         }
1456
1457         /* The Selection panel. Accelerators used: [acgo] wxst */
1458         {
1459             struct ctlpos cp;
1460             ctlposinit(&cp, hwnd, 80, 3, 13);
1461             bartitle(&cp, "Options controlling copy and paste",
1462                      IDC_TITLE_SELECTION);
1463             beginbox(&cp, "Control which mouse button does which thing",
1464                      IDC_BOX_SELECTION1, IDC_BOXT_SELECTION1);
1465             radiobig(&cp, "Action of mouse buttons:", IDC_MBSTATIC,
1466                      "&Windows (Right pastes, Middle extends)", IDC_MBWINDOWS,
1467                      "&xterm (Right extends, Middle pastes)", IDC_MBXTERM,
1468                      NULL);
1469             endbox(&cp);
1470             beginbox(&cp, "Control the select-one-word-at-a-time mode",
1471                      IDC_BOX_SELECTION2, IDC_BOXT_SELECTION2);
1472             charclass(&cp, "Character classes:", IDC_CCSTATIC, IDC_CCLIST,
1473                       "&Set", IDC_CCSET, IDC_CCEDIT,
1474                       "&to class", IDC_CCSTATIC2);
1475             endbox(&cp);
1476
1477             treeview_insert(&tvfaff, 1, "Selection");
1478         }
1479
1480         /* The Colours panel. Accelerators used: [acgo] blum */
1481         {
1482             struct ctlpos cp;
1483             ctlposinit(&cp, hwnd, 80, 3, 13);
1484             bartitle(&cp, "Options controlling use of colours",
1485                      IDC_TITLE_COLOURS);
1486             beginbox(&cp, "General options for colour usage",
1487                      IDC_BOX_COLOURS1, IDC_BOXT_COLOURS1);
1488             checkbox(&cp, "&Bolded text is a different colour", IDC_BOLDCOLOUR);
1489             checkbox(&cp, "Attempt to use &logical palettes", IDC_PALETTE);
1490             endbox(&cp);
1491             beginbox(&cp, "Adjust the precise colours PuTTY displays",
1492                      IDC_BOX_COLOURS2, IDC_BOXT_COLOURS2);
1493             colouredit(&cp, "Select a colo&ur and then click to modify it:",
1494                        IDC_STATIC, IDC_LIST,
1495                        "&Modify...", IDC_CHANGE,
1496                        "Red:", IDC_RSTATIC, IDC_RVALUE,
1497                        "Green:", IDC_GSTATIC, IDC_GVALUE,
1498                        "Blue:", IDC_BSTATIC, IDC_BVALUE, NULL);
1499             endbox(&cp);
1500
1501             treeview_insert(&tvfaff, 1, "Colours");
1502         }
1503
1504         /* The Connection panel. Accelerators used: [acgo] tuk */
1505         {
1506             struct ctlpos cp;
1507             ctlposinit(&cp, hwnd, 80, 3, 13);
1508             bartitle(&cp, "Options controlling the connection", IDC_TITLE_CONNECTION);
1509             if (dlgtype == 0) {
1510                 beginbox(&cp, "Data to send to the server",
1511                          IDC_BOX_CONNECTION1, IDC_BOXT_CONNECTION1);
1512                 staticedit(&cp, "Terminal-&type string", IDC_TTSTATIC, IDC_TTEDIT, 50);
1513                 staticedit(&cp, "Auto-login &username", IDC_LOGSTATIC, IDC_LOGEDIT, 50);
1514                 endbox(&cp);
1515             }
1516             beginbox(&cp, "Sending of null packets to keep session active",
1517                      IDC_BOX_CONNECTION2, IDC_BOXT_CONNECTION2);
1518             staticedit(&cp, "Minutes between &keepalives (0 to turn off)",
1519                        IDC_PINGSTATIC, IDC_PINGEDIT, 25);
1520             endbox(&cp);
1521
1522             treeview_insert(&tvfaff, 0, "Connection");
1523         }
1524
1525         /* The Telnet panel. Accelerators used: [acgo] svldrbf */
1526         {
1527             struct ctlpos cp;
1528             ctlposinit(&cp, hwnd, 80, 3, 13);
1529             if (dlgtype == 0) {
1530                 bartitle(&cp, "Options controlling Telnet connections", IDC_TITLE_TELNET);
1531                 beginbox(&cp, "Data to send to the server",
1532                          IDC_BOX_TELNET1, IDC_BOXT_TELNET1);
1533                 staticedit(&cp, "Terminal-&speed string", IDC_TSSTATIC, IDC_TSEDIT, 50);
1534                 envsetter(&cp, "Environment variables:", IDC_ENVSTATIC,
1535                           "&Variable", IDC_VARSTATIC, IDC_VAREDIT,
1536                           "Va&lue", IDC_VALSTATIC, IDC_VALEDIT,
1537                           IDC_ENVLIST,
1538                           "A&dd", IDC_ENVADD, "&Remove", IDC_ENVREMOVE);
1539                 endbox(&cp);
1540                 beginbox(&cp, "Telnet protocol adjustments",
1541                          IDC_BOX_TELNET2, IDC_BOXT_TELNET2);
1542                 radioline(&cp, "Handling of OLD_ENVIRON ambiguity:", IDC_EMSTATIC, 2,
1543                           "&BSD (commonplace)", IDC_EMBSD,
1544                           "R&FC 1408 (unusual)", IDC_EMRFC, NULL);
1545                 endbox(&cp);
1546
1547                 treeview_insert(&tvfaff, 1, "Telnet");
1548             }
1549         }
1550
1551         /* The SSH panel. Accelerators used: [acgo] rmakwp123bd */
1552         {
1553             struct ctlpos cp;
1554             ctlposinit(&cp, hwnd, 80, 3, 13);
1555             if (dlgtype == 0) {
1556                 bartitle(&cp, "Options controlling SSH connections", IDC_TITLE_SSH);
1557                 beginbox(&cp, "Data to send to the server",
1558                          IDC_BOX_SSH1, IDC_BOXT_SSH1);
1559                 multiedit(&cp,
1560                           "&Remote command:", IDC_CMDSTATIC, IDC_CMDEDIT, 100,
1561                           NULL);
1562                 endbox(&cp);
1563                 beginbox(&cp, "Authentication options",
1564                          IDC_BOX_SSH2, IDC_BOXT_SSH2);
1565                 checkbox(&cp, "Atte&mpt TIS or CryptoCard authentication",
1566                          IDC_AUTHTIS);
1567                 checkbox(&cp, "Allow &agent forwarding", IDC_AGENTFWD);
1568                 editbutton(&cp, "Private &key file for authentication:",
1569                            IDC_PKSTATIC, IDC_PKEDIT, "Bro&wse...", IDC_PKBUTTON);
1570                 endbox(&cp);
1571                 beginbox(&cp, "Protocol options",
1572                          IDC_BOX_SSH3, IDC_BOXT_SSH3);
1573                 checkbox(&cp, "Don't allocate a &pseudo-terminal", IDC_NOPTY);
1574                 radioline(&cp, "Preferred SSH protocol version:",
1575                           IDC_SSHPROTSTATIC, 2,
1576                           "&1", IDC_SSHPROT1, "&2", IDC_SSHPROT2, NULL);
1577                 radioline(&cp, "Preferred encryption algorithm:", IDC_CIPHERSTATIC, 3,
1578                           "&3DES", IDC_CIPHER3DES,
1579                           "&Blowfish", IDC_CIPHERBLOWF,
1580                           "&DES", IDC_CIPHERDES, NULL);
1581                 endbox(&cp);
1582
1583                 treeview_insert(&tvfaff, 1, "SSH");
1584             }
1585         }
1586
1587         init_dlg_ctrls(hwnd);
1588
1589         /*
1590          * Hide all the controls to start with.
1591          */
1592         hide(hwnd, TRUE, controlstartvalue, controlendvalue);
1593
1594         /*
1595          * Put the treeview selection on to the Session panel. This
1596          * should also cause unhiding of the relevant controls.
1597          */
1598         TreeView_SelectItem(treeview, hsession);
1599
1600         /*
1601          * Set focus into the first available control.
1602          */
1603         {
1604             HWND ctl;
1605             ctl = GetDlgItem(hwnd, IDC_HOST);
1606             if (!ctl) ctl = GetDlgItem(hwnd, IDC_CLOSEEXIT);
1607             SetFocus(ctl);
1608         }
1609
1610         SetWindowLong(hwnd, GWL_USERDATA, 1);
1611         return 0;
1612       case WM_LBUTTONUP:
1613         /*
1614          * Button release should trigger WM_OK if there was a
1615          * previous double click on the session list.
1616          */
1617         ReleaseCapture();
1618         if (readytogo)
1619             SendMessage (hwnd, WM_COMMAND, IDOK, 0);
1620         break;
1621       case WM_NOTIFY:
1622         if (LOWORD(wParam) == IDCX_TREEVIEW &&
1623             ((LPNMHDR)lParam)->code == TVN_SELCHANGED) {
1624             HTREEITEM i = TreeView_GetSelection(((LPNMHDR)lParam)->hwndFrom);
1625             TVITEM item;
1626             char buffer[64];
1627             item.hItem = i;
1628             item.pszText = buffer;
1629             item.cchTextMax = sizeof(buffer);
1630             item.mask = TVIF_TEXT;
1631             TreeView_GetItem(((LPNMHDR)lParam)->hwndFrom, &item);
1632             hide(hwnd, TRUE, controlstartvalue, controlendvalue);
1633             if (!strcmp(buffer, "Session"))
1634                 hide(hwnd, FALSE, sessionpanelstart, sessionpanelend);
1635             if (!strcmp(buffer, "Keyboard"))
1636                 hide(hwnd, FALSE, keyboardpanelstart, keyboardpanelend);
1637             if (!strcmp(buffer, "Terminal"))
1638                 hide(hwnd, FALSE, terminalpanelstart, terminalpanelend);
1639             if (!strcmp(buffer, "Window"))
1640                 hide(hwnd, FALSE, windowpanelstart, windowpanelend);
1641             if (!strcmp(buffer, "Connection"))
1642                 hide(hwnd, FALSE, connectionpanelstart, connectionpanelend);
1643             if (!strcmp(buffer, "Telnet"))
1644                 hide(hwnd, FALSE, telnetpanelstart, telnetpanelend);
1645             if (!strcmp(buffer, "SSH"))
1646                 hide(hwnd, FALSE, sshpanelstart, sshpanelend);
1647             if (!strcmp(buffer, "Selection"))
1648                 hide(hwnd, FALSE, selectionpanelstart, selectionpanelend);
1649             if (!strcmp(buffer, "Colours"))
1650                 hide(hwnd, FALSE, colourspanelstart, colourspanelend);
1651             if (!strcmp(buffer, "Translation"))
1652                 hide(hwnd, FALSE, translationpanelstart, translationpanelend);
1653
1654             SetFocus (((LPNMHDR)lParam)->hwndFrom);   /* ensure focus stays */
1655             return 0;
1656         }
1657         break;
1658       case WM_COMMAND:
1659         /*
1660          * Only process WM_COMMAND once the dialog is fully formed.
1661          */
1662         if (GetWindowLong(hwnd, GWL_USERDATA) == 1) switch (LOWORD(wParam)) {
1663           case IDOK:
1664             if (*cfg.host)
1665                 EndDialog (hwnd, 1);
1666             else
1667                 MessageBeep (0);
1668             return 0;
1669           case IDCANCEL:
1670             EndDialog (hwnd, 0);
1671             return 0;
1672           case IDC_PROTTELNET:
1673           case IDC_PROTSSH:
1674           case IDC_PROTRAW:
1675             if (HIWORD(wParam) == BN_CLICKED ||
1676                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1677                 int i = IsDlgButtonChecked (hwnd, IDC_PROTSSH);
1678                 int j = IsDlgButtonChecked (hwnd, IDC_PROTTELNET);
1679                 cfg.protocol = i ? PROT_SSH : j ? PROT_TELNET : PROT_RAW ;
1680                 if ((cfg.protocol == PROT_SSH && cfg.port == 23) ||
1681                     (cfg.protocol == PROT_TELNET && cfg.port == 22)) {
1682                     cfg.port = i ? 22 : 23;
1683                     SetDlgItemInt (hwnd, IDC_PORT, cfg.port, FALSE);
1684                 }
1685             }
1686             break;
1687           case IDC_HOST:
1688             if (HIWORD(wParam) == EN_CHANGE)
1689                 GetDlgItemText (hwnd, IDC_HOST, cfg.host,
1690                                 sizeof(cfg.host)-1);
1691             break;
1692           case IDC_PORT:
1693             if (HIWORD(wParam) == EN_CHANGE)
1694                 MyGetDlgItemInt (hwnd, IDC_PORT, &cfg.port);
1695             break;
1696           case IDC_SESSEDIT:
1697             if (HIWORD(wParam) == EN_CHANGE) {
1698                 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL,
1699                                     (WPARAM) -1, 0);
1700                 GetDlgItemText (hwnd, IDC_SESSEDIT,
1701                                 savedsession, sizeof(savedsession)-1);
1702                 savedsession[sizeof(savedsession)-1] = '\0';
1703             }
1704             break;
1705           case IDC_SESSSAVE:
1706             if (HIWORD(wParam) == BN_CLICKED ||
1707                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1708                 /*
1709                  * Save a session
1710                  */
1711                 char str[2048];
1712                 GetDlgItemText (hwnd, IDC_SESSEDIT, str, sizeof(str)-1);
1713                 if (!*str) {
1714                     int n = SendDlgItemMessage (hwnd, IDC_SESSLIST,
1715                                                 LB_GETCURSEL, 0, 0);
1716                     if (n == LB_ERR) {
1717                         MessageBeep(0);
1718                         break;
1719                     }
1720                     strcpy (str, sessions[n]);
1721                 }
1722                 save_settings (str, !!strcmp(str, "Default Settings"), &cfg);
1723                 get_sesslist (FALSE);
1724                 get_sesslist (TRUE);
1725                 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_RESETCONTENT,
1726                                     0, 0);
1727                 for (i = 0; i < nsessions; i++)
1728                     SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_ADDSTRING,
1729                                         0, (LPARAM) (sessions[i]));
1730                 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL,
1731                                     (WPARAM) -1, 0);
1732             }
1733             break;
1734           case IDC_SESSLIST:
1735           case IDC_SESSLOAD:
1736             if (LOWORD(wParam) == IDC_SESSLOAD &&
1737                 HIWORD(wParam) != BN_CLICKED &&
1738                 HIWORD(wParam) != BN_DOUBLECLICKED)
1739                 break;
1740             if (LOWORD(wParam) == IDC_SESSLIST &&
1741                 HIWORD(wParam) != LBN_DBLCLK)
1742                 break;
1743             {
1744                 int n = SendDlgItemMessage (hwnd, IDC_SESSLIST,
1745                                             LB_GETCURSEL, 0, 0);
1746                 if (n == LB_ERR) {
1747                     MessageBeep(0);
1748                     break;
1749                 }
1750                 load_settings (sessions[n],
1751                                !!strcmp(sessions[n], "Default Settings"),
1752                                &cfg);
1753                 init_dlg_ctrls(hwnd);
1754             }
1755             if (LOWORD(wParam) == IDC_SESSLIST) {
1756                 /*
1757                  * A double-click on a saved session should
1758                  * actually start the session, not just load it.
1759                  * Unless it's Default Settings or some other
1760                  * host-less set of saved settings.
1761                  */
1762                 if (*cfg.host) {
1763                     readytogo = TRUE;
1764                     SetCapture(hwnd);
1765                 }
1766             }
1767             break;
1768           case IDC_SESSDEL:
1769             if (HIWORD(wParam) == BN_CLICKED ||
1770                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1771                 int n = SendDlgItemMessage (hwnd, IDC_SESSLIST,
1772                                             LB_GETCURSEL, 0, 0);
1773                 if (n == LB_ERR || n == 0) {
1774                     MessageBeep(0);
1775                     break;
1776                 }
1777                 del_settings(sessions[n]);
1778                 get_sesslist (FALSE);
1779                 get_sesslist (TRUE);
1780                 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_RESETCONTENT,
1781                                     0, 0);
1782                 for (i = 0; i < nsessions; i++)
1783                     SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_ADDSTRING,
1784                                         0, (LPARAM) (sessions[i]));
1785                 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL,
1786                                     (WPARAM) -1, 0);
1787             }
1788           case IDC_PINGEDIT:
1789             if (HIWORD(wParam) == EN_CHANGE)
1790                 MyGetDlgItemInt (hwnd, IDC_PINGEDIT, &cfg.ping_interval);
1791             break;
1792           case IDC_DEL008:
1793           case IDC_DEL127:
1794             if (HIWORD(wParam) == BN_CLICKED ||
1795                 HIWORD(wParam) == BN_DOUBLECLICKED)
1796                 cfg.bksp_is_delete = IsDlgButtonChecked (hwnd, IDC_DEL127);
1797             break;
1798           case IDC_HOMETILDE:
1799           case IDC_HOMERXVT:
1800             if (HIWORD(wParam) == BN_CLICKED ||
1801                 HIWORD(wParam) == BN_DOUBLECLICKED)
1802                 cfg.rxvt_homeend = IsDlgButtonChecked (hwnd, IDC_HOMERXVT);
1803             break;
1804           case IDC_FUNCXTERM:
1805             if (HIWORD(wParam) == BN_CLICKED ||
1806                 HIWORD(wParam) == BN_DOUBLECLICKED)
1807                 cfg.funky_type = 2;
1808             break;
1809           case IDC_FUNCVT400:
1810             if (HIWORD(wParam) == BN_CLICKED ||
1811                 HIWORD(wParam) == BN_DOUBLECLICKED)
1812                 cfg.funky_type = 3;
1813             break;
1814           case IDC_FUNCTILDE:
1815           case IDC_FUNCLINUX:
1816             if (HIWORD(wParam) == BN_CLICKED ||
1817                 HIWORD(wParam) == BN_DOUBLECLICKED)
1818                 cfg.funky_type = IsDlgButtonChecked (hwnd, IDC_FUNCLINUX);
1819             break;
1820           case IDC_KPNORMAL:
1821           case IDC_KPAPPLIC:
1822             if (HIWORD(wParam) == BN_CLICKED ||
1823                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1824                 cfg.app_keypad = IsDlgButtonChecked (hwnd, IDC_KPAPPLIC);
1825                 cfg.nethack_keypad = FALSE;
1826             }
1827             break;
1828           case IDC_KPNH:
1829             if (HIWORD(wParam) == BN_CLICKED ||
1830                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1831                 cfg.app_keypad = FALSE;
1832                 cfg.nethack_keypad = TRUE;
1833             }
1834             break;
1835           case IDC_CURNORMAL:
1836           case IDC_CURAPPLIC:
1837             if (HIWORD(wParam) == BN_CLICKED ||
1838                 HIWORD(wParam) == BN_DOUBLECLICKED)
1839                 cfg.app_cursor = IsDlgButtonChecked (hwnd, IDC_CURAPPLIC);
1840             break;
1841           case IDC_ALTF4:
1842             if (HIWORD(wParam) == BN_CLICKED ||
1843                 HIWORD(wParam) == BN_DOUBLECLICKED)
1844                 cfg.alt_f4 = IsDlgButtonChecked (hwnd, IDC_ALTF4);
1845             break;
1846           case IDC_ALTSPACE:
1847             if (HIWORD(wParam) == BN_CLICKED ||
1848                 HIWORD(wParam) == BN_DOUBLECLICKED)
1849                 cfg.alt_space = IsDlgButtonChecked (hwnd, IDC_ALTSPACE);
1850             break;
1851           case IDC_LDISCTERM:
1852             if (HIWORD(wParam) == BN_CLICKED ||
1853                 HIWORD(wParam) == BN_DOUBLECLICKED)
1854                 cfg.ldisc_term = IsDlgButtonChecked (hwnd, IDC_LDISCTERM);
1855             break;
1856           case IDC_SCROLLKEY:
1857             if (HIWORD(wParam) == BN_CLICKED ||
1858                 HIWORD(wParam) == BN_DOUBLECLICKED)
1859                 cfg.scroll_on_key = IsDlgButtonChecked (hwnd, IDC_SCROLLKEY);
1860             break;
1861           case IDC_WRAPMODE:
1862             if (HIWORD(wParam) == BN_CLICKED ||
1863                 HIWORD(wParam) == BN_DOUBLECLICKED)
1864                 cfg.wrap_mode = IsDlgButtonChecked (hwnd, IDC_WRAPMODE);
1865             break;
1866           case IDC_DECOM:
1867             if (HIWORD(wParam) == BN_CLICKED ||
1868                 HIWORD(wParam) == BN_DOUBLECLICKED)
1869                 cfg.dec_om = IsDlgButtonChecked (hwnd, IDC_DECOM);
1870             break;
1871           case IDC_LFHASCR:
1872             if (HIWORD(wParam) == BN_CLICKED ||
1873                 HIWORD(wParam) == BN_DOUBLECLICKED)
1874                 cfg.lfhascr = IsDlgButtonChecked (hwnd, IDC_LFHASCR);
1875             break;
1876           case IDC_ROWSEDIT:
1877             if (HIWORD(wParam) == EN_CHANGE)
1878                 MyGetDlgItemInt (hwnd, IDC_ROWSEDIT, &cfg.height);
1879             break;
1880           case IDC_COLSEDIT:
1881             if (HIWORD(wParam) == EN_CHANGE)
1882                 MyGetDlgItemInt (hwnd, IDC_COLSEDIT, &cfg.width);
1883             break;
1884           case IDC_SAVEEDIT:
1885             if (HIWORD(wParam) == EN_CHANGE)
1886                 MyGetDlgItemInt (hwnd, IDC_SAVEEDIT, &cfg.savelines);
1887             break;
1888           case IDC_CHOOSEFONT:
1889             lf.lfHeight = cfg.fontheight;
1890             lf.lfWidth = lf.lfEscapement = lf.lfOrientation = 0;
1891             lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = 0;
1892             lf.lfWeight = (cfg.fontisbold ? FW_BOLD : 0);
1893             lf.lfCharSet = cfg.fontcharset;
1894             lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
1895             lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1896             lf.lfQuality = DEFAULT_QUALITY;
1897             lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
1898             strncpy (lf.lfFaceName, cfg.font, sizeof(lf.lfFaceName)-1);
1899             lf.lfFaceName[sizeof(lf.lfFaceName)-1] = '\0';
1900
1901             cf.lStructSize = sizeof(cf);
1902             cf.hwndOwner = hwnd;
1903             cf.lpLogFont = &lf;
1904             cf.Flags = CF_FIXEDPITCHONLY | CF_FORCEFONTEXIST |
1905                 CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
1906
1907             if (ChooseFont (&cf)) {
1908                 strncpy (cfg.font, lf.lfFaceName, sizeof(cfg.font)-1);
1909                 cfg.font[sizeof(cfg.font)-1] = '\0';
1910                 cfg.fontisbold = (lf.lfWeight == FW_BOLD);
1911                 cfg.fontcharset = lf.lfCharSet;
1912                 cfg.fontheight = lf.lfHeight;
1913                 fmtfont (fontstatic);
1914                 SetDlgItemText (hwnd, IDC_FONTSTATIC, fontstatic);
1915             }
1916             break;
1917           case IDC_BEEP:
1918             if (HIWORD(wParam) == BN_CLICKED ||
1919                 HIWORD(wParam) == BN_DOUBLECLICKED)
1920                 cfg.beep = IsDlgButtonChecked (hwnd, IDC_BEEP);
1921             break;
1922           case IDC_BLINKTEXT:
1923             if (HIWORD(wParam) == BN_CLICKED ||
1924                 HIWORD(wParam) == BN_DOUBLECLICKED)
1925                 cfg.blinktext = IsDlgButtonChecked (hwnd, IDC_BLINKTEXT);
1926             break;
1927           case IDC_BCE:
1928             if (HIWORD(wParam) == BN_CLICKED ||
1929                 HIWORD(wParam) == BN_DOUBLECLICKED)
1930                 cfg.bce = IsDlgButtonChecked (hwnd, IDC_BCE);
1931             break;
1932           case IDC_WINNAME:
1933             if (HIWORD(wParam) == BN_CLICKED ||
1934                 HIWORD(wParam) == BN_DOUBLECLICKED)
1935                 cfg.win_name_always = IsDlgButtonChecked (hwnd, IDC_WINNAME);
1936             break;
1937           case IDC_BLINKCUR:
1938             if (HIWORD(wParam) == BN_CLICKED ||
1939                 HIWORD(wParam) == BN_DOUBLECLICKED)
1940                 cfg.blink_cur = IsDlgButtonChecked (hwnd, IDC_BLINKCUR);
1941             break;
1942           case IDC_SCROLLBAR:
1943             if (HIWORD(wParam) == BN_CLICKED ||
1944                 HIWORD(wParam) == BN_DOUBLECLICKED)
1945                 cfg.scrollbar = IsDlgButtonChecked (hwnd, IDC_SCROLLBAR);
1946             break;
1947           case IDC_LOCKSIZE:
1948              if (HIWORD(wParam) == BN_CLICKED ||
1949                  HIWORD(wParam) == BN_DOUBLECLICKED)
1950                 cfg.locksize = IsDlgButtonChecked (hwnd, IDC_LOCKSIZE);
1951             break;
1952           case IDC_WINEDIT:
1953             if (HIWORD(wParam) == EN_CHANGE)
1954                 GetDlgItemText (hwnd, IDC_WINEDIT, cfg.wintitle,
1955                                 sizeof(cfg.wintitle)-1);
1956             break;
1957           case IDC_CLOSEEXIT:
1958             if (HIWORD(wParam) == BN_CLICKED ||
1959                 HIWORD(wParam) == BN_DOUBLECLICKED)
1960                 cfg.close_on_exit = IsDlgButtonChecked (hwnd, IDC_CLOSEEXIT);
1961             break;
1962           case IDC_CLOSEWARN:
1963             if (HIWORD(wParam) == BN_CLICKED ||
1964                 HIWORD(wParam) == BN_DOUBLECLICKED)
1965                 cfg.warn_on_close = IsDlgButtonChecked (hwnd, IDC_CLOSEWARN);
1966             break;
1967           case IDC_TTEDIT:
1968             if (HIWORD(wParam) == EN_CHANGE)
1969             GetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype,
1970                             sizeof(cfg.termtype)-1);
1971             break;
1972           case IDC_TSEDIT:
1973             if (HIWORD(wParam) == EN_CHANGE)
1974                 GetDlgItemText (hwnd, IDC_TSEDIT, cfg.termspeed,
1975                                 sizeof(cfg.termspeed)-1);
1976             break;
1977           case IDC_LOGEDIT:
1978             if (HIWORD(wParam) == EN_CHANGE)
1979                 GetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username,
1980                                 sizeof(cfg.username)-1);
1981             break;
1982           case IDC_EMBSD:
1983           case IDC_EMRFC:
1984             cfg.rfc_environ = IsDlgButtonChecked (hwnd, IDC_EMRFC);
1985             break;
1986           case IDC_ENVADD:
1987             if (HIWORD(wParam) == BN_CLICKED ||
1988                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1989               char str[sizeof(cfg.environmt)];
1990                 char *p;
1991                 GetDlgItemText (hwnd, IDC_VAREDIT, str, sizeof(str)-1);
1992                 if (!*str) {
1993                     MessageBeep(0);
1994                     break;
1995                 }
1996                 p = str + strlen(str);
1997                 *p++ = '\t';
1998                 GetDlgItemText (hwnd, IDC_VALEDIT, p, sizeof(str)-1-(p-str));
1999                 if (!*p) {
2000                     MessageBeep(0);
2001                     break;
2002                 }
2003               p = cfg.environmt;
2004                 while (*p) {
2005                     while (*p) p++;
2006                     p++;
2007                 }
2008               if ((p-cfg.environmt) + strlen(str) + 2 < sizeof(cfg.environmt)) {
2009                     strcpy (p, str);
2010                     p[strlen(str)+1] = '\0';
2011                     SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_ADDSTRING,
2012                                         0, (LPARAM)str);
2013                     SetDlgItemText (hwnd, IDC_VAREDIT, "");
2014                     SetDlgItemText (hwnd, IDC_VALEDIT, "");
2015                 } else {
2016                     MessageBox(hwnd, "Environment too big", "PuTTY Error",
2017                                MB_OK | MB_ICONERROR);
2018                 }
2019             }
2020             break;
2021           case IDC_ENVREMOVE:
2022             if (HIWORD(wParam) != BN_CLICKED &&
2023                 HIWORD(wParam) != BN_DOUBLECLICKED)
2024                 break;
2025             i = SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_GETCURSEL, 0, 0);
2026             if (i == LB_ERR)
2027                 MessageBeep (0);
2028             else {
2029                 char *p, *q;
2030
2031                 SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_DELETESTRING,
2032                                     i, 0);
2033               p = cfg.environmt;
2034                 while (i > 0) {
2035                     if (!*p)
2036                         goto disaster;
2037                     while (*p) p++;
2038                     p++;
2039                     i--;
2040                 }
2041                 q = p;
2042                 if (!*p)
2043                     goto disaster;
2044                 while (*p) p++;
2045                 p++;
2046                 while (*p) {
2047                     while (*p)
2048                         *q++ = *p++;
2049                     *q++ = *p++;
2050                 }
2051                 *q = '\0';
2052                 disaster:;
2053             }
2054             break;
2055           case IDC_NOPTY:
2056             if (HIWORD(wParam) == BN_CLICKED ||
2057                 HIWORD(wParam) == BN_DOUBLECLICKED)
2058                 cfg.nopty = IsDlgButtonChecked (hwnd, IDC_NOPTY);
2059             break;
2060           case IDC_AGENTFWD:
2061             if (HIWORD(wParam) == BN_CLICKED ||
2062                 HIWORD(wParam) == BN_DOUBLECLICKED)
2063                 cfg.agentfwd = IsDlgButtonChecked (hwnd, IDC_AGENTFWD);
2064             break;
2065           case IDC_CIPHER3DES:
2066           case IDC_CIPHERBLOWF:
2067           case IDC_CIPHERDES:
2068             if (HIWORD(wParam) == BN_CLICKED ||
2069                 HIWORD(wParam) == BN_DOUBLECLICKED) {
2070                 if (IsDlgButtonChecked (hwnd, IDC_CIPHER3DES))
2071                     cfg.cipher = CIPHER_3DES;
2072                 else if (IsDlgButtonChecked (hwnd, IDC_CIPHERBLOWF))
2073                     cfg.cipher = CIPHER_BLOWFISH;
2074                 else if (IsDlgButtonChecked (hwnd, IDC_CIPHERDES))
2075                     cfg.cipher = CIPHER_DES;
2076             }
2077             break;
2078           case IDC_SSHPROT1:
2079           case IDC_SSHPROT2:
2080             if (HIWORD(wParam) == BN_CLICKED ||
2081                 HIWORD(wParam) == BN_DOUBLECLICKED) {
2082                 if (IsDlgButtonChecked (hwnd, IDC_SSHPROT1))
2083                     cfg.sshprot = 1;
2084                 else if (IsDlgButtonChecked (hwnd, IDC_SSHPROT2))
2085                     cfg.sshprot = 2;
2086             }
2087             break;
2088           case IDC_AUTHTIS:
2089             if (HIWORD(wParam) == BN_CLICKED ||
2090                 HIWORD(wParam) == BN_DOUBLECLICKED)
2091                 cfg.try_tis_auth = IsDlgButtonChecked (hwnd, IDC_AUTHTIS);
2092             break;
2093           case IDC_PKEDIT:
2094             if (HIWORD(wParam) == EN_CHANGE)
2095                 GetDlgItemText (hwnd, IDC_PKEDIT, cfg.keyfile,
2096                                 sizeof(cfg.keyfile)-1);
2097             break;
2098           case IDC_CMDEDIT:
2099             if (HIWORD(wParam) == EN_CHANGE)
2100                 GetDlgItemText (hwnd, IDC_CMDEDIT, cfg.remote_cmd,
2101                                 sizeof(cfg.remote_cmd)-1);
2102             break;
2103           case IDC_PKBUTTON:
2104             memset(&of, 0, sizeof(of));
2105 #ifdef OPENFILENAME_SIZE_VERSION_400
2106             of.lStructSize = OPENFILENAME_SIZE_VERSION_400;
2107 #else
2108             of.lStructSize = sizeof(of);
2109 #endif
2110             of.hwndOwner = hwnd;
2111             of.lpstrFilter = "All Files\0*\0\0\0";
2112             of.lpstrCustomFilter = NULL;
2113             of.nFilterIndex = 1;
2114             of.lpstrFile = filename; strcpy(filename, cfg.keyfile);
2115             of.nMaxFile = sizeof(filename);
2116             of.lpstrFileTitle = NULL;
2117             of.lpstrInitialDir = NULL;
2118             of.lpstrTitle = "Select Public Key File";
2119             of.Flags = 0;
2120             if (GetOpenFileName(&of)) {
2121                 strcpy(cfg.keyfile, filename);
2122                 SetDlgItemText (hwnd, IDC_PKEDIT, cfg.keyfile);
2123             }
2124             break;
2125           case IDC_MBWINDOWS:
2126           case IDC_MBXTERM:
2127             cfg.mouse_is_xterm = IsDlgButtonChecked (hwnd, IDC_MBXTERM);
2128             break;
2129           case IDC_CCSET:
2130             {
2131                 BOOL ok;
2132                 int i;
2133                 int n = GetDlgItemInt (hwnd, IDC_CCEDIT, &ok, FALSE);
2134
2135                 if (!ok)
2136                     MessageBeep (0);
2137                 else {
2138                     for (i=0; i<256; i++)
2139                         if (SendDlgItemMessage (hwnd, IDC_CCLIST, LB_GETSEL,
2140                                                 i, 0)) {
2141                             char str[100];
2142                             cfg.wordness[i] = n;
2143                             SendDlgItemMessage (hwnd, IDC_CCLIST,
2144                                                 LB_DELETESTRING, i, 0);
2145                             sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
2146                                     (i>=0x21 && i != 0x7F) ? i : ' ',
2147                                     cfg.wordness[i]);
2148                             SendDlgItemMessage (hwnd, IDC_CCLIST,
2149                                                 LB_INSERTSTRING, i,
2150                                                 (LPARAM)str);
2151                         }
2152                 }
2153             }
2154             break;
2155           case IDC_BOLDCOLOUR:
2156             if (HIWORD(wParam) == BN_CLICKED ||
2157                 HIWORD(wParam) == BN_DOUBLECLICKED) {
2158                 int n, i;
2159                 cfg.bold_colour = IsDlgButtonChecked (hwnd, IDC_BOLDCOLOUR);
2160                 n = SendDlgItemMessage (hwnd, IDC_LIST, LB_GETCOUNT, 0, 0);
2161                 if (cfg.bold_colour && n!=22) {
2162                     for (i=0; i<22; i++)
2163                         if (!permcolour[i])
2164                             SendDlgItemMessage (hwnd, IDC_LIST,
2165                                                 LB_INSERTSTRING, i,
2166                                                 (LPARAM) colours[i]);
2167                 } else if (!cfg.bold_colour && n!=12) {
2168                     for (i=22; i-- ;)
2169                         if (!permcolour[i])
2170                             SendDlgItemMessage (hwnd, IDC_LIST,
2171                                                 LB_DELETESTRING, i, 0);
2172                 }
2173             }
2174             break;
2175           case IDC_PALETTE:
2176             if (HIWORD(wParam) == BN_CLICKED ||
2177                 HIWORD(wParam) == BN_DOUBLECLICKED)
2178                 cfg.try_palette = IsDlgButtonChecked (hwnd, IDC_PALETTE);
2179             break;
2180           case IDC_LIST:
2181             if (HIWORD(wParam) == LBN_DBLCLK ||
2182                 HIWORD(wParam) == LBN_SELCHANGE) {
2183                 int i = SendDlgItemMessage (hwnd, IDC_LIST, LB_GETCURSEL,
2184                                             0, 0);
2185                 if (!cfg.bold_colour)
2186                     i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
2187                 SetDlgItemInt (hwnd, IDC_RVALUE, cfg.colours[i][0], FALSE);
2188                 SetDlgItemInt (hwnd, IDC_GVALUE, cfg.colours[i][1], FALSE);
2189                 SetDlgItemInt (hwnd, IDC_BVALUE, cfg.colours[i][2], FALSE);
2190             }
2191             break;
2192           case IDC_CHANGE:
2193             if (HIWORD(wParam) == BN_CLICKED ||
2194                 HIWORD(wParam) == BN_DOUBLECLICKED) {
2195                 static CHOOSECOLOR cc;
2196                 static DWORD custom[16] = {0};   /* zero initialisers */
2197                 int i = SendDlgItemMessage (hwnd, IDC_LIST, LB_GETCURSEL,
2198                                             0, 0);
2199                 if (!cfg.bold_colour)
2200                     i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
2201                 cc.lStructSize = sizeof(cc);
2202                 cc.hwndOwner = hwnd;
2203                 cc.hInstance = (HWND)hinst;
2204                 cc.lpCustColors = custom;
2205                 cc.rgbResult = RGB (cfg.colours[i][0], cfg.colours[i][1],
2206                                     cfg.colours[i][2]);
2207                 cc.Flags = CC_FULLOPEN | CC_RGBINIT;
2208                 if (ChooseColor(&cc)) {
2209                     cfg.colours[i][0] =
2210                         (unsigned char) (cc.rgbResult & 0xFF);
2211                     cfg.colours[i][1] =
2212                         (unsigned char) (cc.rgbResult >> 8) & 0xFF;
2213                     cfg.colours[i][2] =
2214                         (unsigned char) (cc.rgbResult >> 16) & 0xFF;
2215                     SetDlgItemInt (hwnd, IDC_RVALUE, cfg.colours[i][0],
2216                                    FALSE);
2217                     SetDlgItemInt (hwnd, IDC_GVALUE, cfg.colours[i][1],
2218                                    FALSE);
2219                     SetDlgItemInt (hwnd, IDC_BVALUE, cfg.colours[i][2],
2220                                    FALSE);
2221                 }
2222             }
2223             break;
2224           case IDC_NOXLAT:
2225           case IDC_KOI8WIN1251:
2226           case IDC_88592WIN1250:
2227           case IDC_88592CP852:
2228             cfg.xlat_enablekoiwin =
2229                 IsDlgButtonChecked (hwnd, IDC_KOI8WIN1251);
2230             cfg.xlat_88592w1250 =
2231                 IsDlgButtonChecked (hwnd, IDC_88592WIN1250);
2232             cfg.xlat_88592cp852 =
2233                 IsDlgButtonChecked (hwnd, IDC_88592CP852);
2234             break;
2235           case IDC_CAPSLOCKCYR:
2236             if (HIWORD(wParam) == BN_CLICKED ||
2237                 HIWORD(wParam) == BN_DOUBLECLICKED) {
2238                 cfg.xlat_capslockcyr =
2239                     IsDlgButtonChecked (hwnd, IDC_CAPSLOCKCYR);
2240             }
2241             break;
2242           case IDC_VTXWINDOWS:
2243           case IDC_VTOEMANSI:
2244           case IDC_VTOEMONLY:
2245           case IDC_VTPOORMAN:
2246             cfg.vtmode =
2247                 (IsDlgButtonChecked (hwnd, IDC_VTXWINDOWS) ? VT_XWINDOWS :
2248                  IsDlgButtonChecked (hwnd, IDC_VTOEMANSI) ? VT_OEMANSI :
2249                  IsDlgButtonChecked (hwnd, IDC_VTOEMONLY) ? VT_OEMONLY :
2250                  VT_POORMAN);
2251             break;
2252         }
2253         return 0;
2254       case WM_CLOSE:
2255         EndDialog (hwnd, 0);
2256         return 0;
2257
2258         /* Grrr Explorer will maximize Dialogs! */
2259       case WM_SIZE:
2260         if (wParam == SIZE_MAXIMIZED)
2261            force_normal(hwnd);
2262         return 0;
2263     }
2264     return 0;
2265 }
2266
2267 static int CALLBACK MainDlgProc (HWND hwnd, UINT msg,
2268                                  WPARAM wParam, LPARAM lParam) {
2269     static HWND page = NULL;
2270
2271     if (msg == WM_COMMAND && LOWORD(wParam) == IDOK) {
2272     }
2273     if (msg == WM_COMMAND && LOWORD(wParam) == IDCX_ABOUT) {
2274         EnableWindow(hwnd, 0);
2275         DialogBox(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
2276                   GetParent(hwnd), AboutProc);
2277         EnableWindow(hwnd, 1);
2278         SetActiveWindow(hwnd);
2279     }
2280     return GenericMainDlgProc (hwnd, msg, wParam, lParam, 0);
2281 }
2282
2283 static int CALLBACK ReconfDlgProc (HWND hwnd, UINT msg,
2284                                    WPARAM wParam, LPARAM lParam) {
2285     static HWND page;
2286     return GenericMainDlgProc (hwnd, msg, wParam, lParam, 1);
2287 }
2288
2289 int do_config (void) {
2290     int ret;
2291
2292     get_sesslist(TRUE);
2293     savedsession[0] = '\0';
2294     ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_MAINBOX), NULL, MainDlgProc);
2295     get_sesslist(FALSE);
2296
2297     return ret;
2298 }
2299
2300 int do_reconfig (HWND hwnd) {
2301     Config backup_cfg;
2302     int ret;
2303
2304     backup_cfg = cfg;                  /* structure copy */
2305     ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_RECONF), hwnd, ReconfDlgProc);
2306     if (!ret)
2307         cfg = backup_cfg;              /* structure copy */
2308     else
2309         force_normal(hwnd);
2310
2311     return ret;
2312 }
2313
2314 void logevent (char *string) {
2315     if (nevents >= negsize) {
2316         negsize += 64;
2317         events = srealloc (events, negsize * sizeof(*events));
2318     }
2319     events[nevents] = smalloc(1+strlen(string));
2320     strcpy (events[nevents], string);
2321     nevents++;
2322     if (logbox) {
2323         int count;
2324         SendDlgItemMessage (logbox, IDN_LIST, LB_ADDSTRING,
2325                             0, (LPARAM)string);
2326         count = SendDlgItemMessage (logbox, IDN_LIST, LB_GETCOUNT, 0, 0);
2327         SendDlgItemMessage (logbox, IDN_LIST, LB_SETTOPINDEX, count-1, 0);
2328     }
2329 }
2330
2331 void showeventlog (HWND hwnd) {
2332     if (!logbox) {
2333         logbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_LOGBOX),
2334                                hwnd, LogProc);
2335         ShowWindow (logbox, SW_SHOWNORMAL);
2336     }
2337 }
2338
2339 void showabout (HWND hwnd) {
2340     if (!abtbox) {
2341         abtbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
2342                                hwnd, AboutProc);
2343         ShowWindow (abtbox, SW_SHOWNORMAL);
2344     }
2345 }
2346
2347 void verify_ssh_host_key(char *host, int port, char *keytype,
2348                          char *keystr, char *fingerprint) {
2349     int ret;
2350
2351     static const char absentmsg[] =
2352         "The server's host key is not cached in the registry. You\n"
2353         "have no guarantee that the server is the computer you\n"
2354         "think it is.\n"
2355         "The server's key fingerprint is:\n"
2356         "%s\n"
2357         "If you trust this host, hit Yes to add the key to\n"
2358         "PuTTY's cache and carry on connecting.\n"
2359         "If you do not trust this host, hit No to abandon the\n"
2360         "connection.\n";
2361
2362     static const char wrongmsg[] =
2363         "WARNING - POTENTIAL SECURITY BREACH!\n"
2364         "\n"
2365         "The server's host key does not match the one PuTTY has\n"
2366         "cached in the registry. This means that either the\n"
2367         "server administrator has changed the host key, or you\n"
2368         "have actually connected to another computer pretending\n"
2369         "to be the server.\n"
2370         "The new key fingerprint is:\n"
2371         "%s\n"
2372         "If you were expecting this change and trust the new key,\n"
2373         "hit Yes to update PuTTY's cache and continue connecting.\n"
2374         "If you want to carry on connecting but without updating\n"
2375         "the cache, hit No.\n"
2376         "If you want to abandon the connection completely, hit\n"
2377         "Cancel. Hitting Cancel is the ONLY guaranteed safe\n"
2378         "choice.\n";
2379
2380     static const char mbtitle[] = "PuTTY Security Alert";
2381
2382     
2383     char message[160+                  /* sensible fingerprint max size */
2384                  (sizeof(absentmsg) > sizeof(wrongmsg) ?
2385                   sizeof(absentmsg) : sizeof(wrongmsg))];
2386
2387     /*
2388      * Verify the key against the registry.
2389      */
2390     ret = verify_host_key(host, port, keytype, keystr);
2391
2392     if (ret == 0)                      /* success - key matched OK */
2393         return;
2394     if (ret == 2) {                    /* key was different */
2395         int mbret;
2396         sprintf(message, wrongmsg, fingerprint);
2397         mbret = MessageBox(NULL, message, mbtitle,
2398                            MB_ICONWARNING | MB_YESNOCANCEL);
2399         if (mbret == IDYES)
2400             store_host_key(host, port, keytype, keystr);
2401         if (mbret == IDCANCEL)
2402             exit(0);
2403     }
2404     if (ret == 1) {                    /* key was absent */
2405         int mbret;
2406         sprintf(message, absentmsg, fingerprint);
2407         mbret = MessageBox(NULL, message, mbtitle,
2408                            MB_ICONWARNING | MB_YESNO);
2409         if (mbret == IDNO)
2410             exit(0);
2411         store_host_key(host, port, keytype, keystr);
2412     }
2413 }