]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - windlg.c
0821b79a5ac8a20d867fdc8b43504573890fe92d
[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_CAPSLOCKCYR,
1001     IDC_VTSTATIC,
1002     IDC_VTXWINDOWS,
1003     IDC_VTOEMANSI,
1004     IDC_VTOEMONLY,
1005     IDC_VTPOORMAN,
1006     translationpanelend,
1007
1008     controlendvalue
1009 };
1010
1011 static const char *const colours[] = {
1012     "Default Foreground", "Default Bold Foreground",
1013     "Default Background", "Default Bold Background",
1014     "Cursor Text", "Cursor Colour",
1015     "ANSI Black", "ANSI Black Bold",
1016     "ANSI Red", "ANSI Red Bold",
1017     "ANSI Green", "ANSI Green Bold",
1018     "ANSI Yellow", "ANSI Yellow Bold",
1019     "ANSI Blue", "ANSI Blue Bold",
1020     "ANSI Magenta", "ANSI Magenta Bold",
1021     "ANSI Cyan", "ANSI Cyan Bold",
1022     "ANSI White", "ANSI White Bold"
1023 };
1024 static const int permcolour[] = {
1025     TRUE, FALSE, TRUE, FALSE, TRUE, TRUE,
1026     TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE,
1027     TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE
1028 };
1029
1030 static void fmtfont (char *buf) {
1031     sprintf (buf, "Font: %s, ", cfg.font);
1032     if (cfg.fontisbold)
1033         strcat(buf, "bold, ");
1034     if (cfg.fontheight == 0)
1035         strcat (buf, "default height");
1036     else
1037         sprintf (buf+strlen(buf), "%d-%s",
1038                  (cfg.fontheight < 0 ? -cfg.fontheight : cfg.fontheight),
1039                  (cfg.fontheight < 0 ? "pixel" : "point"));
1040 }
1041
1042 static void init_dlg_ctrls(HWND hwnd) {
1043     int i;
1044     char fontstatic[256];
1045
1046     SetDlgItemText (hwnd, IDC_HOST, cfg.host);
1047     SetDlgItemText (hwnd, IDC_SESSEDIT, savedsession);
1048     SetDlgItemInt (hwnd, IDC_PORT, cfg.port, FALSE);
1049     for (i = 0; i < nsessions; i++)
1050         SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_ADDSTRING,
1051                             0, (LPARAM) (sessions[i]));
1052     CheckRadioButton (hwnd, IDC_PROTRAW, IDC_PROTSSH,
1053                       cfg.protocol==PROT_SSH ? IDC_PROTSSH :
1054                       cfg.protocol==PROT_TELNET ? IDC_PROTTELNET : IDC_PROTRAW );
1055     SetDlgItemInt (hwnd, IDC_PINGEDIT, cfg.ping_interval, FALSE);
1056
1057     CheckRadioButton (hwnd, IDC_DEL008, IDC_DEL127,
1058                       cfg.bksp_is_delete ? IDC_DEL127 : IDC_DEL008);
1059     CheckRadioButton (hwnd, IDC_HOMETILDE, IDC_HOMERXVT,
1060                       cfg.rxvt_homeend ? IDC_HOMERXVT : IDC_HOMETILDE);
1061     CheckRadioButton (hwnd, IDC_FUNCTILDE, IDC_FUNCXTERM,
1062                       cfg.funky_type == 0 ? IDC_FUNCTILDE :
1063                       cfg.funky_type == 1 ? IDC_FUNCLINUX :
1064                       cfg.funky_type == 2 ? IDC_FUNCXTERM :
1065                       cfg.funky_type == 3 ? IDC_FUNCVT400 :
1066                       IDC_FUNCTILDE );
1067     CheckRadioButton (hwnd, IDC_CURNORMAL, IDC_CURAPPLIC,
1068                       cfg.app_cursor ? IDC_CURAPPLIC : IDC_CURNORMAL);
1069     CheckRadioButton (hwnd, IDC_KPNORMAL, IDC_KPNH,
1070                       cfg.nethack_keypad ? IDC_KPNH :
1071                       cfg.app_keypad ? IDC_KPAPPLIC : IDC_KPNORMAL);
1072     CheckDlgButton (hwnd, IDC_ALTF4, cfg.alt_f4);
1073     CheckDlgButton (hwnd, IDC_ALTSPACE, cfg.alt_space);
1074     CheckDlgButton (hwnd, IDC_LDISCTERM, cfg.ldisc_term);
1075     CheckDlgButton (hwnd, IDC_SCROLLKEY, cfg.scroll_on_key);
1076
1077     CheckDlgButton (hwnd, IDC_WRAPMODE, cfg.wrap_mode);
1078     CheckDlgButton (hwnd, IDC_DECOM, cfg.dec_om);
1079     CheckDlgButton (hwnd, IDC_LFHASCR, cfg.lfhascr);
1080     SetDlgItemInt (hwnd, IDC_ROWSEDIT, cfg.height, FALSE);
1081     SetDlgItemInt (hwnd, IDC_COLSEDIT, cfg.width, FALSE);
1082     SetDlgItemInt (hwnd, IDC_SAVEEDIT, cfg.savelines, FALSE);
1083     fmtfont (fontstatic);
1084     SetDlgItemText (hwnd, IDC_FONTSTATIC, fontstatic);
1085     CheckDlgButton (hwnd, IDC_BEEP, cfg.beep);
1086     CheckDlgButton (hwnd, IDC_BCE, cfg.bce);
1087     CheckDlgButton (hwnd, IDC_BLINKTEXT, cfg.blinktext);
1088
1089     SetDlgItemText (hwnd, IDC_WINEDIT, cfg.wintitle);
1090     CheckDlgButton (hwnd, IDC_WINNAME, cfg.win_name_always);
1091     CheckDlgButton (hwnd, IDC_BLINKCUR, cfg.blink_cur);
1092     CheckDlgButton (hwnd, IDC_SCROLLBAR, cfg.scrollbar);
1093     CheckDlgButton (hwnd, IDC_LOCKSIZE, cfg.locksize);
1094     CheckDlgButton (hwnd, IDC_CLOSEEXIT, cfg.close_on_exit);
1095     CheckDlgButton (hwnd, IDC_CLOSEWARN, cfg.warn_on_close);
1096
1097     SetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype);
1098     SetDlgItemText (hwnd, IDC_TSEDIT, cfg.termspeed);
1099     SetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username);
1100     {
1101         char *p = cfg.environmt;
1102         while (*p) {
1103             SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_ADDSTRING, 0,
1104                                 (LPARAM) p);
1105             p += strlen(p)+1;
1106         }
1107     }
1108     CheckRadioButton (hwnd, IDC_EMBSD, IDC_EMRFC,
1109                       cfg.rfc_environ ? IDC_EMRFC : IDC_EMBSD);
1110
1111     SetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype);
1112     SetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username);
1113     CheckDlgButton (hwnd, IDC_NOPTY, cfg.nopty);
1114     CheckDlgButton (hwnd, IDC_AGENTFWD, cfg.agentfwd);
1115     CheckRadioButton (hwnd, IDC_CIPHER3DES, IDC_CIPHERDES,
1116                       cfg.cipher == CIPHER_BLOWFISH ? IDC_CIPHERBLOWF :
1117                       cfg.cipher == CIPHER_DES ? IDC_CIPHERDES :
1118                       IDC_CIPHER3DES);
1119     CheckRadioButton (hwnd, IDC_SSHPROT1, IDC_SSHPROT2,
1120                       cfg.sshprot == 1 ? IDC_SSHPROT1 : IDC_SSHPROT2);
1121     CheckDlgButton (hwnd, IDC_AUTHTIS, cfg.try_tis_auth);
1122     SetDlgItemText (hwnd, IDC_PKEDIT, cfg.keyfile);
1123     SetDlgItemText (hwnd, IDC_CMDEDIT, cfg.remote_cmd);
1124
1125     CheckRadioButton (hwnd, IDC_MBWINDOWS, IDC_MBXTERM,
1126                       cfg.mouse_is_xterm ? IDC_MBXTERM : IDC_MBWINDOWS);
1127     {
1128         static int tabs[4] = {25, 61, 96, 128};
1129         SendDlgItemMessage (hwnd, IDC_CCLIST, LB_SETTABSTOPS, 4,
1130                             (LPARAM) tabs);
1131     }
1132     for (i=0; i<256; i++) {
1133         char str[100];
1134         sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
1135                 (i>=0x21 && i != 0x7F) ? i : ' ',
1136                 cfg.wordness[i]);
1137         SendDlgItemMessage (hwnd, IDC_CCLIST, LB_ADDSTRING, 0,
1138                             (LPARAM) str);
1139     }
1140
1141     CheckDlgButton (hwnd, IDC_BOLDCOLOUR, cfg.bold_colour);
1142     CheckDlgButton (hwnd, IDC_PALETTE, cfg.try_palette);
1143     {
1144         int i;
1145         for (i=0; i<22; i++)
1146             if (cfg.bold_colour || permcolour[i])
1147                 SendDlgItemMessage (hwnd, IDC_LIST, LB_ADDSTRING, 0,
1148                                     (LPARAM) colours[i]);
1149     }
1150     SendDlgItemMessage (hwnd, IDC_LIST, LB_SETCURSEL, 0, 0);
1151     SetDlgItemInt (hwnd, IDC_RVALUE, cfg.colours[0][0], FALSE);
1152     SetDlgItemInt (hwnd, IDC_GVALUE, cfg.colours[0][1], FALSE);
1153     SetDlgItemInt (hwnd, IDC_BVALUE, cfg.colours[0][2], FALSE);
1154
1155     CheckRadioButton (hwnd, IDC_NOXLAT, IDC_88592WIN1250,
1156                       cfg.xlat_88592w1250 ? IDC_88592WIN1250 :
1157                       cfg.xlat_enablekoiwin ? IDC_KOI8WIN1251 :
1158                       IDC_NOXLAT);
1159     CheckDlgButton (hwnd, IDC_CAPSLOCKCYR, cfg.xlat_capslockcyr);
1160     CheckRadioButton (hwnd, IDC_VTXWINDOWS, IDC_VTPOORMAN,
1161                       cfg.vtmode == VT_XWINDOWS ? IDC_VTXWINDOWS :
1162                       cfg.vtmode == VT_OEMANSI ? IDC_VTOEMANSI :
1163                       cfg.vtmode == VT_OEMONLY ? IDC_VTOEMONLY :
1164                       IDC_VTPOORMAN);
1165 }
1166
1167 static void hide(HWND hwnd, int hide, int minid, int maxid) {
1168     int i;
1169     for (i = minid; i < maxid; i++) {
1170         HWND ctl = GetDlgItem(hwnd, i);
1171         if (ctl) {
1172             ShowWindow(ctl, hide ? SW_HIDE : SW_SHOW);
1173         }
1174     }
1175 }
1176
1177 struct treeview_faff {
1178     HWND treeview;
1179     HTREEITEM lastat[4];
1180 };
1181
1182 static HTREEITEM treeview_insert(struct treeview_faff *faff,
1183                                  int level, char *text) {
1184     TVINSERTSTRUCT ins;
1185     int i;
1186     HTREEITEM newitem;
1187     ins.hParent = (level > 0 ? faff->lastat[level-1] : TVI_ROOT);
1188     ins.hInsertAfter = faff->lastat[level];
1189 #if _WIN32_IE >= 0x0400 && defined NONAMELESSUNION
1190 #define INSITEM DUMMYUNIONNAME.item
1191 #else
1192 #define INSITEM item
1193 #endif
1194     ins.INSITEM.mask = TVIF_TEXT;
1195     ins.INSITEM.pszText = text;
1196     newitem = TreeView_InsertItem(faff->treeview, &ins);
1197     if (level > 0)
1198         TreeView_Expand(faff->treeview, faff->lastat[level-1], TVE_EXPAND);
1199     faff->lastat[level] = newitem;
1200     for (i = level+1; i < 4; i++) faff->lastat[i] = NULL;
1201     return newitem;
1202 }
1203
1204 /*
1205  * This _huge_ function is the configuration box.
1206  */
1207 static int GenericMainDlgProc (HWND hwnd, UINT msg,
1208                                WPARAM wParam, LPARAM lParam,
1209                                int dlgtype) {
1210     HWND hw, treeview;
1211     struct treeview_faff tvfaff;
1212     HTREEITEM hsession;
1213     OPENFILENAME of;
1214     char filename[sizeof(cfg.keyfile)];
1215     CHOOSEFONT cf;
1216     LOGFONT lf;
1217     char fontstatic[256];
1218     int i;
1219
1220     switch (msg) {
1221       case WM_INITDIALOG:
1222         SetWindowLong(hwnd, GWL_USERDATA, 0);
1223         /*
1224          * Centre the window.
1225          */
1226         {                              /* centre the window */
1227             RECT rs, rd;
1228
1229             hw = GetDesktopWindow();
1230             if (GetWindowRect (hw, &rs) && GetWindowRect (hwnd, &rd))
1231                 MoveWindow (hwnd, (rs.right + rs.left + rd.left - rd.right)/2,
1232                             (rs.bottom + rs.top + rd.top - rd.bottom)/2,
1233                             rd.right-rd.left, rd.bottom-rd.top, TRUE);
1234         }
1235
1236         /*
1237          * Create the tree view.
1238          */
1239         {
1240             RECT r;
1241             WPARAM font;
1242             HWND tvstatic;
1243
1244             r.left = 3; r.right = r.left + 75;
1245             r.top = 3; r.bottom = r.top + 10;
1246             MapDialogRect(hwnd, &r);
1247             tvstatic = CreateWindowEx(0, "STATIC", "Cate&gory:",
1248                                       WS_CHILD | WS_VISIBLE,
1249                                       r.left, r.top,
1250                                       r.right-r.left, r.bottom-r.top,
1251                                       hwnd, (HMENU)IDCX_TVSTATIC, hinst, NULL);
1252             font = SendMessage(hwnd, WM_GETFONT, 0, 0);
1253             SendMessage(tvstatic, WM_SETFONT, font, MAKELPARAM(TRUE, 0));
1254
1255             r.left = 3; r.right = r.left + 75;
1256             r.top = 13; r.bottom = r.top + 196;
1257             MapDialogRect(hwnd, &r);
1258             treeview = CreateWindowEx(WS_EX_CLIENTEDGE, WC_TREEVIEW, "",
1259                                       WS_CHILD | WS_VISIBLE |
1260                                       WS_TABSTOP | TVS_HASLINES |
1261                                       TVS_DISABLEDRAGDROP | TVS_HASBUTTONS |
1262                                       TVS_LINESATROOT | TVS_SHOWSELALWAYS,
1263                                       r.left, r.top,
1264                                       r.right-r.left, r.bottom-r.top,
1265                                       hwnd, (HMENU)IDCX_TREEVIEW, hinst, NULL);
1266             font = SendMessage(hwnd, WM_GETFONT, 0, 0);
1267             SendMessage(treeview, WM_SETFONT, font, MAKELPARAM(TRUE, 0));
1268             tvfaff.treeview = treeview;
1269             memset(tvfaff.lastat, 0, sizeof(tvfaff.lastat));
1270         }
1271
1272         /*
1273          * Create the various panelfuls of controls.
1274          */
1275
1276         /* The Session panel. Accelerators used: [acgo] nprthelsdx */
1277         {
1278             struct ctlpos cp;
1279             ctlposinit(&cp, hwnd, 80, 3, 13);
1280             bartitle(&cp, "Basic options for your PuTTY session",
1281                      IDC_TITLE_SESSION);
1282             if (dlgtype == 0) {
1283                 beginbox(&cp, "Specify your connection by host name",
1284                          IDC_BOX_SESSION1, IDC_BOXT_SESSION1);
1285                 multiedit(&cp,
1286                           "Host &Name", IDC_HOSTSTATIC, IDC_HOST, 75,
1287                           "&Port", IDC_PORTSTATIC, IDC_PORT, 25, NULL);
1288                 if (backends[2].backend == NULL) {
1289                     /* this is PuTTYtel, so only two protocols available */
1290                     radioline(&cp, "Protocol:", IDC_PROTSTATIC, 3,
1291                               "&Raw", IDC_PROTRAW,
1292                               "&Telnet", IDC_PROTTELNET, NULL);
1293                 } else {
1294                     radioline(&cp, "Protocol:", IDC_PROTSTATIC, 3,
1295                               "&Raw", IDC_PROTRAW,
1296                               "&Telnet", IDC_PROTTELNET,
1297 #ifdef FWHACK
1298                               "SS&H/hack",
1299 #else
1300                               "SS&H",
1301 #endif
1302                               IDC_PROTSSH, NULL);
1303                 }
1304                 endbox(&cp);
1305                 beginbox(&cp, "Load, save or delete a stored session",
1306                          IDC_BOX_SESSION2, IDC_BOXT_SESSION2);
1307                 sesssaver(&cp, "Stor&ed Sessions",
1308                           IDC_SESSSTATIC, IDC_SESSEDIT, IDC_SESSLIST,
1309                           "&Load", IDC_SESSLOAD,
1310                           "&Save", IDC_SESSSAVE,
1311                           "&Delete", IDC_SESSDEL, NULL);
1312                 endbox(&cp);
1313             }
1314             beginbox(&cp, NULL, IDC_BOX_SESSION3, 0);
1315             checkbox(&cp, "Close Window on E&xit", IDC_CLOSEEXIT);
1316             endbox(&cp);
1317
1318             hsession = treeview_insert(&tvfaff, 0, "Session");
1319         }
1320
1321         /* The Terminal panel. Accelerators used: [acgo] rmkh&dlbenu */
1322         {
1323             struct ctlpos cp;
1324             ctlposinit(&cp, hwnd, 80, 3, 13);
1325             bartitle(&cp, "Options controlling the terminal emulation",
1326                      IDC_TITLE_TERMINAL);
1327             beginbox(&cp, "Set the size of the terminal window",
1328                      IDC_BOX_TERMINAL1, IDC_BOXT_TERMINAL1);
1329             multiedit(&cp,
1330                       "&Rows", IDC_ROWSSTATIC, IDC_ROWSEDIT, 50,
1331                       "Colu&mns", IDC_COLSSTATIC, IDC_COLSEDIT, 50,
1332                       NULL);
1333             checkbox(&cp, "Loc&k window size against resizing", IDC_LOCKSIZE);
1334             endbox(&cp);
1335             beginbox(&cp, "Set the font used in the terminal window",
1336                      IDC_BOX_TERMINAL2, IDC_BOXT_TERMINAL2);
1337             staticbtn(&cp, "", IDC_FONTSTATIC, "C&hange...", IDC_CHOOSEFONT);
1338             endbox(&cp);
1339             beginbox(&cp, "Set various terminal options",
1340                      IDC_BOX_TERMINAL3, IDC_BOXT_TERMINAL3);
1341             checkbox(&cp, "Auto &wrap mode initially on", IDC_WRAPMODE);
1342             checkbox(&cp, "&DEC Origin Mode initially on", IDC_DECOM);
1343             checkbox(&cp, "Implicit CR in every &LF", IDC_LFHASCR);
1344             checkbox(&cp, "&Beep enabled", IDC_BEEP);
1345             checkbox(&cp, "Use background colour to &erase screen", IDC_BCE);
1346             checkbox(&cp, "Enable bli&nking text", IDC_BLINKTEXT);
1347             checkbox(&cp, "&Use local terminal line discipline", IDC_LDISCTERM);
1348             endbox(&cp);
1349
1350             treeview_insert(&tvfaff, 0, "Terminal");
1351         }
1352
1353         /* The Keyboard panel. Accelerators used: [acgo] h?srvlxvnpmie */
1354         {
1355             struct ctlpos cp;
1356             ctlposinit(&cp, hwnd, 80, 3, 13);
1357             bartitle(&cp, "Options controlling the effects of keys",
1358                      IDC_TITLE_KEYBOARD);
1359             beginbox(&cp, "Change the sequences sent by:",
1360                      IDC_BOX_KEYBOARD1, IDC_BOXT_KEYBOARD1);
1361             radioline(&cp, "The Backspace key", IDC_DELSTATIC, 2,
1362                       "Control-&H", IDC_DEL008,
1363                       "Control-&? (127)", IDC_DEL127, NULL);
1364             radioline(&cp, "The Home and End keys", IDC_HOMESTATIC, 2,
1365                       "&Standard", IDC_HOMETILDE,
1366                       "&rxvt", IDC_HOMERXVT, NULL);
1367             radioline(&cp, "The Function keys and keypad", IDC_FUNCSTATIC, 4,
1368                       "&VT400", IDC_FUNCTILDE,
1369                       "&Linux", IDC_FUNCLINUX,
1370                       "&Xterm R6", IDC_FUNCXTERM,
1371                       "&VT400", IDC_FUNCVT400, NULL);
1372             endbox(&cp);
1373             beginbox(&cp, "Change the initial state of:",
1374                      IDC_BOX_KEYBOARD2, IDC_BOXT_KEYBOARD2);
1375             radioline(&cp, "Initial state of cursor keys:", IDC_CURSTATIC, 2,
1376                       "&Normal", IDC_CURNORMAL,
1377                       "A&pplication", IDC_CURAPPLIC, NULL);
1378             radioline(&cp, "Initial state of numeric keypad:", IDC_KPSTATIC, 3,
1379                       "Nor&mal", IDC_KPNORMAL,
1380                       "Appl&ication", IDC_KPAPPLIC,
1381                       "N&etHack", IDC_KPNH, NULL);
1382             endbox(&cp);
1383
1384             treeview_insert(&tvfaff, 1, "Keyboard");
1385         }
1386
1387         /* The Window panel. Accelerators used: [acgo] tibsdkw4y */
1388         {
1389             struct ctlpos cp;
1390             ctlposinit(&cp, hwnd, 80, 3, 13);
1391             bartitle(&cp, "Options controlling PuTTY's window",
1392                      IDC_TITLE_WINDOW);
1393             beginbox(&cp, "Adjust the use of the window title",
1394                      IDC_BOX_WINDOW1, IDC_BOXT_WINDOW1);
1395             if (dlgtype == 0)
1396                 multiedit(&cp,
1397                           "Initial window &title:", IDC_WINTITLE,
1398                           IDC_WINEDIT, 100, NULL);
1399             checkbox(&cp, "Avoid ever using &icon title", IDC_WINNAME);
1400             endbox(&cp);
1401             beginbox(&cp, "Adjust the use of the cursor",
1402                      IDC_BOX_WINDOW2, IDC_BOXT_WINDOW2);
1403             checkbox(&cp, "Cursor &blinks", IDC_BLINKCUR);
1404             endbox(&cp);
1405             beginbox(&cp, "Control the scrollback in the window",
1406                      IDC_BOX_WINDOW3, IDC_BOXT_WINDOW3);
1407             staticedit(&cp, "Lines of &scrollback",
1408                        IDC_SAVESTATIC, IDC_SAVEEDIT, 50);
1409             checkbox(&cp, "&Display scrollbar", IDC_SCROLLBAR);
1410             checkbox(&cp, "Reset scrollback on &keypress", IDC_SCROLLKEY);
1411             endbox(&cp);
1412             beginbox(&cp, NULL, IDC_BOX_WINDOW4, 0);
1413             checkbox(&cp, "&Warn before closing window", IDC_CLOSEWARN);
1414             checkbox(&cp, "Window closes on ALT-F&4", IDC_ALTF4);
1415             checkbox(&cp, "S&ystem menu appears on ALT-Space)", IDC_ALTSPACE);
1416             endbox(&cp);
1417
1418             treeview_insert(&tvfaff, 0, "Window");
1419         }
1420
1421         /* The Translation panel. Accelerators used: [acgo] xbepnkis */
1422         {
1423             struct ctlpos cp;
1424             ctlposinit(&cp, hwnd, 80, 3, 13);
1425             bartitle(&cp, "Options controlling character set translation",
1426                      IDC_TITLE_TRANSLATION);
1427             beginbox(&cp, "Adjust how PuTTY displays line drawing characters",
1428                      IDC_BOX_TRANSLATION1, IDC_BOXT_TRANSLATION1);
1429             radiobig(&cp,
1430                      "Handling of line drawing characters:", IDC_VTSTATIC,
1431                      "Font has &XWindows encoding", IDC_VTXWINDOWS,
1432                      "Use font in &both ANSI and OEM modes", IDC_VTOEMANSI,
1433                      "Use font in O&EM mode only", IDC_VTOEMONLY,
1434                      "&Poor man's line drawing (""+"", ""-"" and ""|"")",
1435                      IDC_VTPOORMAN, NULL);
1436             endbox(&cp);
1437             beginbox(&cp, "Enable character set translation on received data",
1438                      IDC_BOX_TRANSLATION2, IDC_BOXT_TRANSLATION2);
1439             radiobig(&cp,
1440                      "Character set translation:", IDC_XLATSTATIC,
1441                      "&None", IDC_NOXLAT,
1442                      "&KOI8 / Win-1251", IDC_KOI8WIN1251,
1443                      "&ISO-8859-2 / Win-1250", IDC_88592WIN1250, NULL);
1444             endbox(&cp);
1445             beginbox(&cp, "Enable character set translation on input data",
1446                      IDC_BOX_TRANSLATION3, IDC_BOXT_TRANSLATION3);
1447             checkbox(&cp, "CAP&S LOCK acts as cyrillic switch",
1448                      IDC_CAPSLOCKCYR);
1449             endbox(&cp);
1450
1451             treeview_insert(&tvfaff, 1, "Translation");
1452         }
1453
1454         /* The Selection panel. Accelerators used: [acgo] wxst */
1455         {
1456             struct ctlpos cp;
1457             ctlposinit(&cp, hwnd, 80, 3, 13);
1458             bartitle(&cp, "Options controlling copy and paste",
1459                      IDC_TITLE_SELECTION);
1460             beginbox(&cp, "Control which mouse button does which thing",
1461                      IDC_BOX_SELECTION1, IDC_BOXT_SELECTION1);
1462             radiobig(&cp, "Action of mouse buttons:", IDC_MBSTATIC,
1463                      "&Windows (Right pastes, Middle extends)", IDC_MBWINDOWS,
1464                      "&xterm (Right extends, Middle pastes)", IDC_MBXTERM,
1465                      NULL);
1466             endbox(&cp);
1467             beginbox(&cp, "Control the select-one-word-at-a-time mode",
1468                      IDC_BOX_SELECTION2, IDC_BOXT_SELECTION2);
1469             charclass(&cp, "Character classes:", IDC_CCSTATIC, IDC_CCLIST,
1470                       "&Set", IDC_CCSET, IDC_CCEDIT,
1471                       "&to class", IDC_CCSTATIC2);
1472             endbox(&cp);
1473
1474             treeview_insert(&tvfaff, 1, "Selection");
1475         }
1476
1477         /* The Colours panel. Accelerators used: [acgo] blum */
1478         {
1479             struct ctlpos cp;
1480             ctlposinit(&cp, hwnd, 80, 3, 13);
1481             bartitle(&cp, "Options controlling use of colours",
1482                      IDC_TITLE_COLOURS);
1483             beginbox(&cp, "General options for colour usage",
1484                      IDC_BOX_COLOURS1, IDC_BOXT_COLOURS1);
1485             checkbox(&cp, "&Bolded text is a different colour", IDC_BOLDCOLOUR);
1486             checkbox(&cp, "Attempt to use &logical palettes", IDC_PALETTE);
1487             endbox(&cp);
1488             beginbox(&cp, "Adjust the precise colours PuTTY displays",
1489                      IDC_BOX_COLOURS2, IDC_BOXT_COLOURS2);
1490             colouredit(&cp, "Select a colo&ur and then click to modify it:",
1491                        IDC_STATIC, IDC_LIST,
1492                        "&Modify...", IDC_CHANGE,
1493                        "Red:", IDC_RSTATIC, IDC_RVALUE,
1494                        "Green:", IDC_GSTATIC, IDC_GVALUE,
1495                        "Blue:", IDC_BSTATIC, IDC_BVALUE, NULL);
1496             endbox(&cp);
1497
1498             treeview_insert(&tvfaff, 1, "Colours");
1499         }
1500
1501         /* The Connection panel. Accelerators used: [acgo] tuk */
1502         {
1503             struct ctlpos cp;
1504             ctlposinit(&cp, hwnd, 80, 3, 13);
1505             bartitle(&cp, "Options controlling the connection", IDC_TITLE_CONNECTION);
1506             if (dlgtype == 0) {
1507                 beginbox(&cp, "Data to send to the server",
1508                          IDC_BOX_CONNECTION1, IDC_BOXT_CONNECTION1);
1509                 staticedit(&cp, "Terminal-&type string", IDC_TTSTATIC, IDC_TTEDIT, 50);
1510                 staticedit(&cp, "Auto-login &username", IDC_LOGSTATIC, IDC_LOGEDIT, 50);
1511                 endbox(&cp);
1512             }
1513             beginbox(&cp, "Sending of null packets to keep session active",
1514                      IDC_BOX_CONNECTION2, IDC_BOXT_CONNECTION2);
1515             staticedit(&cp, "Minutes between &keepalives (0 to turn off)",
1516                        IDC_PINGSTATIC, IDC_PINGEDIT, 25);
1517             endbox(&cp);
1518
1519             treeview_insert(&tvfaff, 0, "Connection");
1520         }
1521
1522         /* The Telnet panel. Accelerators used: [acgo] svldrbf */
1523         {
1524             struct ctlpos cp;
1525             ctlposinit(&cp, hwnd, 80, 3, 13);
1526             if (dlgtype == 0) {
1527                 bartitle(&cp, "Options controlling Telnet connections", IDC_TITLE_TELNET);
1528                 beginbox(&cp, "Data to send to the server",
1529                          IDC_BOX_TELNET1, IDC_BOXT_TELNET1);
1530                 staticedit(&cp, "Terminal-&speed string", IDC_TSSTATIC, IDC_TSEDIT, 50);
1531                 envsetter(&cp, "Environment variables:", IDC_ENVSTATIC,
1532                           "&Variable", IDC_VARSTATIC, IDC_VAREDIT,
1533                           "Va&lue", IDC_VALSTATIC, IDC_VALEDIT,
1534                           IDC_ENVLIST,
1535                           "A&dd", IDC_ENVADD, "&Remove", IDC_ENVREMOVE);
1536                 endbox(&cp);
1537                 beginbox(&cp, "Telnet protocol adjustments",
1538                          IDC_BOX_TELNET2, IDC_BOXT_TELNET2);
1539                 radioline(&cp, "Handling of OLD_ENVIRON ambiguity:", IDC_EMSTATIC, 2,
1540                           "&BSD (commonplace)", IDC_EMBSD,
1541                           "R&FC 1408 (unusual)", IDC_EMRFC, NULL);
1542                 endbox(&cp);
1543
1544                 treeview_insert(&tvfaff, 1, "Telnet");
1545             }
1546         }
1547
1548         /* The SSH panel. Accelerators used: [acgo] rmakwp123bd */
1549         {
1550             struct ctlpos cp;
1551             ctlposinit(&cp, hwnd, 80, 3, 13);
1552             if (dlgtype == 0) {
1553                 bartitle(&cp, "Options controlling SSH connections", IDC_TITLE_SSH);
1554                 beginbox(&cp, "Data to send to the server",
1555                          IDC_BOX_SSH1, IDC_BOXT_SSH1);
1556                 multiedit(&cp,
1557                           "&Remote command:", IDC_CMDSTATIC, IDC_CMDEDIT, 100,
1558                           NULL);
1559                 endbox(&cp);
1560                 beginbox(&cp, "Authentication options",
1561                          IDC_BOX_SSH2, IDC_BOXT_SSH2);
1562                 checkbox(&cp, "Atte&mpt TIS or CryptoCard authentication",
1563                          IDC_AUTHTIS);
1564                 checkbox(&cp, "Allow &agent forwarding", IDC_AGENTFWD);
1565                 editbutton(&cp, "Private &key file for authentication:",
1566                            IDC_PKSTATIC, IDC_PKEDIT, "Bro&wse...", IDC_PKBUTTON);
1567                 endbox(&cp);
1568                 beginbox(&cp, "Protocol options",
1569                          IDC_BOX_SSH3, IDC_BOXT_SSH3);
1570                 checkbox(&cp, "Don't allocate a &pseudo-terminal", IDC_NOPTY);
1571                 radioline(&cp, "Preferred SSH protocol version:",
1572                           IDC_SSHPROTSTATIC, 2,
1573                           "&1", IDC_SSHPROT1, "&2", IDC_SSHPROT2, NULL);
1574                 radioline(&cp, "Preferred encryption algorithm:", IDC_CIPHERSTATIC, 3,
1575                           "&3DES", IDC_CIPHER3DES,
1576                           "&Blowfish", IDC_CIPHERBLOWF,
1577                           "&DES", IDC_CIPHERDES, NULL);
1578                 endbox(&cp);
1579
1580                 treeview_insert(&tvfaff, 1, "SSH");
1581             }
1582         }
1583
1584         init_dlg_ctrls(hwnd);
1585
1586         /*
1587          * Hide all the controls to start with.
1588          */
1589         hide(hwnd, TRUE, controlstartvalue, controlendvalue);
1590
1591         /*
1592          * Put the treeview selection on to the Session panel. This
1593          * should also cause unhiding of the relevant controls.
1594          */
1595         TreeView_SelectItem(treeview, hsession);
1596
1597         /*
1598          * Set focus into the first available control.
1599          */
1600         {
1601             HWND ctl;
1602             ctl = GetDlgItem(hwnd, IDC_HOST);
1603             if (!ctl) ctl = GetDlgItem(hwnd, IDC_CLOSEEXIT);
1604             SetFocus(ctl);
1605         }
1606
1607         SetWindowLong(hwnd, GWL_USERDATA, 1);
1608         return 0;
1609       case WM_LBUTTONUP:
1610         /*
1611          * Button release should trigger WM_OK if there was a
1612          * previous double click on the session list.
1613          */
1614         ReleaseCapture();
1615         if (readytogo)
1616             SendMessage (hwnd, WM_COMMAND, IDOK, 0);
1617         break;
1618       case WM_NOTIFY:
1619         if (LOWORD(wParam) == IDCX_TREEVIEW &&
1620             ((LPNMHDR)lParam)->code == TVN_SELCHANGED) {
1621             HTREEITEM i = TreeView_GetSelection(((LPNMHDR)lParam)->hwndFrom);
1622             TVITEM item;
1623             char buffer[64];
1624             item.hItem = i;
1625             item.pszText = buffer;
1626             item.cchTextMax = sizeof(buffer);
1627             item.mask = TVIF_TEXT;
1628             TreeView_GetItem(((LPNMHDR)lParam)->hwndFrom, &item);
1629             hide(hwnd, TRUE, controlstartvalue, controlendvalue);
1630             if (!strcmp(buffer, "Session"))
1631                 hide(hwnd, FALSE, sessionpanelstart, sessionpanelend);
1632             if (!strcmp(buffer, "Keyboard"))
1633                 hide(hwnd, FALSE, keyboardpanelstart, keyboardpanelend);
1634             if (!strcmp(buffer, "Terminal"))
1635                 hide(hwnd, FALSE, terminalpanelstart, terminalpanelend);
1636             if (!strcmp(buffer, "Window"))
1637                 hide(hwnd, FALSE, windowpanelstart, windowpanelend);
1638             if (!strcmp(buffer, "Connection"))
1639                 hide(hwnd, FALSE, connectionpanelstart, connectionpanelend);
1640             if (!strcmp(buffer, "Telnet"))
1641                 hide(hwnd, FALSE, telnetpanelstart, telnetpanelend);
1642             if (!strcmp(buffer, "SSH"))
1643                 hide(hwnd, FALSE, sshpanelstart, sshpanelend);
1644             if (!strcmp(buffer, "Selection"))
1645                 hide(hwnd, FALSE, selectionpanelstart, selectionpanelend);
1646             if (!strcmp(buffer, "Colours"))
1647                 hide(hwnd, FALSE, colourspanelstart, colourspanelend);
1648             if (!strcmp(buffer, "Translation"))
1649                 hide(hwnd, FALSE, translationpanelstart, translationpanelend);
1650
1651             SetFocus (((LPNMHDR)lParam)->hwndFrom);   /* ensure focus stays */
1652             return 0;
1653         }
1654         break;
1655       case WM_COMMAND:
1656         /*
1657          * Only process WM_COMMAND once the dialog is fully formed.
1658          */
1659         if (GetWindowLong(hwnd, GWL_USERDATA) == 1) switch (LOWORD(wParam)) {
1660           case IDOK:
1661             if (*cfg.host)
1662                 EndDialog (hwnd, 1);
1663             else
1664                 MessageBeep (0);
1665             return 0;
1666           case IDCANCEL:
1667             EndDialog (hwnd, 0);
1668             return 0;
1669           case IDC_PROTTELNET:
1670           case IDC_PROTSSH:
1671           case IDC_PROTRAW:
1672             if (HIWORD(wParam) == BN_CLICKED ||
1673                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1674                 int i = IsDlgButtonChecked (hwnd, IDC_PROTSSH);
1675                 int j = IsDlgButtonChecked (hwnd, IDC_PROTTELNET);
1676                 cfg.protocol = i ? PROT_SSH : j ? PROT_TELNET : PROT_RAW ;
1677                 if ((cfg.protocol == PROT_SSH && cfg.port == 23) ||
1678                     (cfg.protocol == PROT_TELNET && cfg.port == 22)) {
1679                     cfg.port = i ? 22 : 23;
1680                     SetDlgItemInt (hwnd, IDC_PORT, cfg.port, FALSE);
1681                 }
1682             }
1683             break;
1684           case IDC_HOST:
1685             if (HIWORD(wParam) == EN_CHANGE)
1686                 GetDlgItemText (hwnd, IDC_HOST, cfg.host,
1687                                 sizeof(cfg.host)-1);
1688             break;
1689           case IDC_PORT:
1690             if (HIWORD(wParam) == EN_CHANGE)
1691                 MyGetDlgItemInt (hwnd, IDC_PORT, &cfg.port);
1692             break;
1693           case IDC_SESSEDIT:
1694             if (HIWORD(wParam) == EN_CHANGE) {
1695                 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL,
1696                                     (WPARAM) -1, 0);
1697                 GetDlgItemText (hwnd, IDC_SESSEDIT,
1698                                 savedsession, sizeof(savedsession)-1);
1699                 savedsession[sizeof(savedsession)-1] = '\0';
1700             }
1701             break;
1702           case IDC_SESSSAVE:
1703             if (HIWORD(wParam) == BN_CLICKED ||
1704                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1705                 /*
1706                  * Save a session
1707                  */
1708                 char str[2048];
1709                 GetDlgItemText (hwnd, IDC_SESSEDIT, str, sizeof(str)-1);
1710                 if (!*str) {
1711                     int n = SendDlgItemMessage (hwnd, IDC_SESSLIST,
1712                                                 LB_GETCURSEL, 0, 0);
1713                     if (n == LB_ERR) {
1714                         MessageBeep(0);
1715                         break;
1716                     }
1717                     strcpy (str, sessions[n]);
1718                 }
1719                 save_settings (str, !!strcmp(str, "Default Settings"), &cfg);
1720                 get_sesslist (FALSE);
1721                 get_sesslist (TRUE);
1722                 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_RESETCONTENT,
1723                                     0, 0);
1724                 for (i = 0; i < nsessions; i++)
1725                     SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_ADDSTRING,
1726                                         0, (LPARAM) (sessions[i]));
1727                 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL,
1728                                     (WPARAM) -1, 0);
1729             }
1730             break;
1731           case IDC_SESSLIST:
1732           case IDC_SESSLOAD:
1733             if (LOWORD(wParam) == IDC_SESSLOAD &&
1734                 HIWORD(wParam) != BN_CLICKED &&
1735                 HIWORD(wParam) != BN_DOUBLECLICKED)
1736                 break;
1737             if (LOWORD(wParam) == IDC_SESSLIST &&
1738                 HIWORD(wParam) != LBN_DBLCLK)
1739                 break;
1740             {
1741                 int n = SendDlgItemMessage (hwnd, IDC_SESSLIST,
1742                                             LB_GETCURSEL, 0, 0);
1743                 if (n == LB_ERR) {
1744                     MessageBeep(0);
1745                     break;
1746                 }
1747                 load_settings (sessions[n],
1748                                !!strcmp(sessions[n], "Default Settings"),
1749                                &cfg);
1750                 init_dlg_ctrls(hwnd);
1751             }
1752             if (LOWORD(wParam) == IDC_SESSLIST) {
1753                 /*
1754                  * A double-click on a saved session should
1755                  * actually start the session, not just load it.
1756                  * Unless it's Default Settings or some other
1757                  * host-less set of saved settings.
1758                  */
1759                 if (*cfg.host) {
1760                     readytogo = TRUE;
1761                     SetCapture(hwnd);
1762                 }
1763             }
1764             break;
1765           case IDC_SESSDEL:
1766             if (HIWORD(wParam) == BN_CLICKED ||
1767                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1768                 int n = SendDlgItemMessage (hwnd, IDC_SESSLIST,
1769                                             LB_GETCURSEL, 0, 0);
1770                 if (n == LB_ERR || n == 0) {
1771                     MessageBeep(0);
1772                     break;
1773                 }
1774                 del_settings(sessions[n]);
1775                 get_sesslist (FALSE);
1776                 get_sesslist (TRUE);
1777                 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_RESETCONTENT,
1778                                     0, 0);
1779                 for (i = 0; i < nsessions; i++)
1780                     SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_ADDSTRING,
1781                                         0, (LPARAM) (sessions[i]));
1782                 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL,
1783                                     (WPARAM) -1, 0);
1784             }
1785           case IDC_PINGEDIT:
1786             if (HIWORD(wParam) == EN_CHANGE)
1787                 MyGetDlgItemInt (hwnd, IDC_PINGEDIT, &cfg.ping_interval);
1788             break;
1789           case IDC_DEL008:
1790           case IDC_DEL127:
1791             if (HIWORD(wParam) == BN_CLICKED ||
1792                 HIWORD(wParam) == BN_DOUBLECLICKED)
1793                 cfg.bksp_is_delete = IsDlgButtonChecked (hwnd, IDC_DEL127);
1794             break;
1795           case IDC_HOMETILDE:
1796           case IDC_HOMERXVT:
1797             if (HIWORD(wParam) == BN_CLICKED ||
1798                 HIWORD(wParam) == BN_DOUBLECLICKED)
1799                 cfg.rxvt_homeend = IsDlgButtonChecked (hwnd, IDC_HOMERXVT);
1800             break;
1801           case IDC_FUNCXTERM:
1802             if (HIWORD(wParam) == BN_CLICKED ||
1803                 HIWORD(wParam) == BN_DOUBLECLICKED)
1804                 cfg.funky_type = 2;
1805             break;
1806           case IDC_FUNCVT400:
1807             if (HIWORD(wParam) == BN_CLICKED ||
1808                 HIWORD(wParam) == BN_DOUBLECLICKED)
1809                 cfg.funky_type = 3;
1810             break;
1811           case IDC_FUNCTILDE:
1812           case IDC_FUNCLINUX:
1813             if (HIWORD(wParam) == BN_CLICKED ||
1814                 HIWORD(wParam) == BN_DOUBLECLICKED)
1815                 cfg.funky_type = IsDlgButtonChecked (hwnd, IDC_FUNCLINUX);
1816             break;
1817           case IDC_KPNORMAL:
1818           case IDC_KPAPPLIC:
1819             if (HIWORD(wParam) == BN_CLICKED ||
1820                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1821                 cfg.app_keypad = IsDlgButtonChecked (hwnd, IDC_KPAPPLIC);
1822                 cfg.nethack_keypad = FALSE;
1823             }
1824             break;
1825           case IDC_KPNH:
1826             if (HIWORD(wParam) == BN_CLICKED ||
1827                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1828                 cfg.app_keypad = FALSE;
1829                 cfg.nethack_keypad = TRUE;
1830             }
1831             break;
1832           case IDC_CURNORMAL:
1833           case IDC_CURAPPLIC:
1834             if (HIWORD(wParam) == BN_CLICKED ||
1835                 HIWORD(wParam) == BN_DOUBLECLICKED)
1836                 cfg.app_cursor = IsDlgButtonChecked (hwnd, IDC_CURAPPLIC);
1837             break;
1838           case IDC_ALTF4:
1839             if (HIWORD(wParam) == BN_CLICKED ||
1840                 HIWORD(wParam) == BN_DOUBLECLICKED)
1841                 cfg.alt_f4 = IsDlgButtonChecked (hwnd, IDC_ALTF4);
1842             break;
1843           case IDC_ALTSPACE:
1844             if (HIWORD(wParam) == BN_CLICKED ||
1845                 HIWORD(wParam) == BN_DOUBLECLICKED)
1846                 cfg.alt_space = IsDlgButtonChecked (hwnd, IDC_ALTSPACE);
1847             break;
1848           case IDC_LDISCTERM:
1849             if (HIWORD(wParam) == BN_CLICKED ||
1850                 HIWORD(wParam) == BN_DOUBLECLICKED)
1851                 cfg.ldisc_term = IsDlgButtonChecked (hwnd, IDC_LDISCTERM);
1852             break;
1853           case IDC_SCROLLKEY:
1854             if (HIWORD(wParam) == BN_CLICKED ||
1855                 HIWORD(wParam) == BN_DOUBLECLICKED)
1856                 cfg.scroll_on_key = IsDlgButtonChecked (hwnd, IDC_SCROLLKEY);
1857             break;
1858           case IDC_WRAPMODE:
1859             if (HIWORD(wParam) == BN_CLICKED ||
1860                 HIWORD(wParam) == BN_DOUBLECLICKED)
1861                 cfg.wrap_mode = IsDlgButtonChecked (hwnd, IDC_WRAPMODE);
1862             break;
1863           case IDC_DECOM:
1864             if (HIWORD(wParam) == BN_CLICKED ||
1865                 HIWORD(wParam) == BN_DOUBLECLICKED)
1866                 cfg.dec_om = IsDlgButtonChecked (hwnd, IDC_DECOM);
1867             break;
1868           case IDC_LFHASCR:
1869             if (HIWORD(wParam) == BN_CLICKED ||
1870                 HIWORD(wParam) == BN_DOUBLECLICKED)
1871                 cfg.lfhascr = IsDlgButtonChecked (hwnd, IDC_LFHASCR);
1872             break;
1873           case IDC_ROWSEDIT:
1874             if (HIWORD(wParam) == EN_CHANGE)
1875                 MyGetDlgItemInt (hwnd, IDC_ROWSEDIT, &cfg.height);
1876             break;
1877           case IDC_COLSEDIT:
1878             if (HIWORD(wParam) == EN_CHANGE)
1879                 MyGetDlgItemInt (hwnd, IDC_COLSEDIT, &cfg.width);
1880             break;
1881           case IDC_SAVEEDIT:
1882             if (HIWORD(wParam) == EN_CHANGE)
1883                 MyGetDlgItemInt (hwnd, IDC_SAVEEDIT, &cfg.savelines);
1884             break;
1885           case IDC_CHOOSEFONT:
1886             lf.lfHeight = cfg.fontheight;
1887             lf.lfWidth = lf.lfEscapement = lf.lfOrientation = 0;
1888             lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = 0;
1889             lf.lfWeight = (cfg.fontisbold ? FW_BOLD : 0);
1890             lf.lfCharSet = cfg.fontcharset;
1891             lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
1892             lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1893             lf.lfQuality = DEFAULT_QUALITY;
1894             lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
1895             strncpy (lf.lfFaceName, cfg.font, sizeof(lf.lfFaceName)-1);
1896             lf.lfFaceName[sizeof(lf.lfFaceName)-1] = '\0';
1897
1898             cf.lStructSize = sizeof(cf);
1899             cf.hwndOwner = hwnd;
1900             cf.lpLogFont = &lf;
1901             cf.Flags = CF_FIXEDPITCHONLY | CF_FORCEFONTEXIST |
1902                 CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
1903
1904             if (ChooseFont (&cf)) {
1905                 strncpy (cfg.font, lf.lfFaceName, sizeof(cfg.font)-1);
1906                 cfg.font[sizeof(cfg.font)-1] = '\0';
1907                 cfg.fontisbold = (lf.lfWeight == FW_BOLD);
1908                 cfg.fontcharset = lf.lfCharSet;
1909                 cfg.fontheight = lf.lfHeight;
1910                 fmtfont (fontstatic);
1911                 SetDlgItemText (hwnd, IDC_FONTSTATIC, fontstatic);
1912             }
1913             break;
1914           case IDC_BEEP:
1915             if (HIWORD(wParam) == BN_CLICKED ||
1916                 HIWORD(wParam) == BN_DOUBLECLICKED)
1917                 cfg.beep = IsDlgButtonChecked (hwnd, IDC_BEEP);
1918             break;
1919           case IDC_BLINKTEXT:
1920             if (HIWORD(wParam) == BN_CLICKED ||
1921                 HIWORD(wParam) == BN_DOUBLECLICKED)
1922                 cfg.blinktext = IsDlgButtonChecked (hwnd, IDC_BLINKTEXT);
1923             break;
1924           case IDC_BCE:
1925             if (HIWORD(wParam) == BN_CLICKED ||
1926                 HIWORD(wParam) == BN_DOUBLECLICKED)
1927                 cfg.bce = IsDlgButtonChecked (hwnd, IDC_BCE);
1928             break;
1929           case IDC_WINNAME:
1930             if (HIWORD(wParam) == BN_CLICKED ||
1931                 HIWORD(wParam) == BN_DOUBLECLICKED)
1932                 cfg.win_name_always = IsDlgButtonChecked (hwnd, IDC_WINNAME);
1933             break;
1934           case IDC_BLINKCUR:
1935             if (HIWORD(wParam) == BN_CLICKED ||
1936                 HIWORD(wParam) == BN_DOUBLECLICKED)
1937                 cfg.blink_cur = IsDlgButtonChecked (hwnd, IDC_BLINKCUR);
1938             break;
1939           case IDC_SCROLLBAR:
1940             if (HIWORD(wParam) == BN_CLICKED ||
1941                 HIWORD(wParam) == BN_DOUBLECLICKED)
1942                 cfg.scrollbar = IsDlgButtonChecked (hwnd, IDC_SCROLLBAR);
1943             break;
1944           case IDC_LOCKSIZE:
1945              if (HIWORD(wParam) == BN_CLICKED ||
1946                  HIWORD(wParam) == BN_DOUBLECLICKED)
1947                 cfg.locksize = IsDlgButtonChecked (hwnd, IDC_LOCKSIZE);
1948             break;
1949           case IDC_WINEDIT:
1950             if (HIWORD(wParam) == EN_CHANGE)
1951                 GetDlgItemText (hwnd, IDC_WINEDIT, cfg.wintitle,
1952                                 sizeof(cfg.wintitle)-1);
1953             break;
1954           case IDC_CLOSEEXIT:
1955             if (HIWORD(wParam) == BN_CLICKED ||
1956                 HIWORD(wParam) == BN_DOUBLECLICKED)
1957                 cfg.close_on_exit = IsDlgButtonChecked (hwnd, IDC_CLOSEEXIT);
1958             break;
1959           case IDC_CLOSEWARN:
1960             if (HIWORD(wParam) == BN_CLICKED ||
1961                 HIWORD(wParam) == BN_DOUBLECLICKED)
1962                 cfg.warn_on_close = IsDlgButtonChecked (hwnd, IDC_CLOSEWARN);
1963             break;
1964           case IDC_TTEDIT:
1965             if (HIWORD(wParam) == EN_CHANGE)
1966             GetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype,
1967                             sizeof(cfg.termtype)-1);
1968             break;
1969           case IDC_TSEDIT:
1970             if (HIWORD(wParam) == EN_CHANGE)
1971                 GetDlgItemText (hwnd, IDC_TSEDIT, cfg.termspeed,
1972                                 sizeof(cfg.termspeed)-1);
1973             break;
1974           case IDC_LOGEDIT:
1975             if (HIWORD(wParam) == EN_CHANGE)
1976                 GetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username,
1977                                 sizeof(cfg.username)-1);
1978             break;
1979           case IDC_EMBSD:
1980           case IDC_EMRFC:
1981             cfg.rfc_environ = IsDlgButtonChecked (hwnd, IDC_EMRFC);
1982             break;
1983           case IDC_ENVADD:
1984             if (HIWORD(wParam) == BN_CLICKED ||
1985                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1986               char str[sizeof(cfg.environmt)];
1987                 char *p;
1988                 GetDlgItemText (hwnd, IDC_VAREDIT, str, sizeof(str)-1);
1989                 if (!*str) {
1990                     MessageBeep(0);
1991                     break;
1992                 }
1993                 p = str + strlen(str);
1994                 *p++ = '\t';
1995                 GetDlgItemText (hwnd, IDC_VALEDIT, p, sizeof(str)-1-(p-str));
1996                 if (!*p) {
1997                     MessageBeep(0);
1998                     break;
1999                 }
2000               p = cfg.environmt;
2001                 while (*p) {
2002                     while (*p) p++;
2003                     p++;
2004                 }
2005               if ((p-cfg.environmt) + strlen(str) + 2 < sizeof(cfg.environmt)) {
2006                     strcpy (p, str);
2007                     p[strlen(str)+1] = '\0';
2008                     SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_ADDSTRING,
2009                                         0, (LPARAM)str);
2010                     SetDlgItemText (hwnd, IDC_VAREDIT, "");
2011                     SetDlgItemText (hwnd, IDC_VALEDIT, "");
2012                 } else {
2013                     MessageBox(hwnd, "Environment too big", "PuTTY Error",
2014                                MB_OK | MB_ICONERROR);
2015                 }
2016             }
2017             break;
2018           case IDC_ENVREMOVE:
2019             if (HIWORD(wParam) != BN_CLICKED &&
2020                 HIWORD(wParam) != BN_DOUBLECLICKED)
2021                 break;
2022             i = SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_GETCURSEL, 0, 0);
2023             if (i == LB_ERR)
2024                 MessageBeep (0);
2025             else {
2026                 char *p, *q;
2027
2028                 SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_DELETESTRING,
2029                                     i, 0);
2030               p = cfg.environmt;
2031                 while (i > 0) {
2032                     if (!*p)
2033                         goto disaster;
2034                     while (*p) p++;
2035                     p++;
2036                     i--;
2037                 }
2038                 q = p;
2039                 if (!*p)
2040                     goto disaster;
2041                 while (*p) p++;
2042                 p++;
2043                 while (*p) {
2044                     while (*p)
2045                         *q++ = *p++;
2046                     *q++ = *p++;
2047                 }
2048                 *q = '\0';
2049                 disaster:;
2050             }
2051             break;
2052           case IDC_NOPTY:
2053             if (HIWORD(wParam) == BN_CLICKED ||
2054                 HIWORD(wParam) == BN_DOUBLECLICKED)
2055                 cfg.nopty = IsDlgButtonChecked (hwnd, IDC_NOPTY);
2056             break;
2057           case IDC_AGENTFWD:
2058             if (HIWORD(wParam) == BN_CLICKED ||
2059                 HIWORD(wParam) == BN_DOUBLECLICKED)
2060                 cfg.agentfwd = IsDlgButtonChecked (hwnd, IDC_AGENTFWD);
2061             break;
2062           case IDC_CIPHER3DES:
2063           case IDC_CIPHERBLOWF:
2064           case IDC_CIPHERDES:
2065             if (HIWORD(wParam) == BN_CLICKED ||
2066                 HIWORD(wParam) == BN_DOUBLECLICKED) {
2067                 if (IsDlgButtonChecked (hwnd, IDC_CIPHER3DES))
2068                     cfg.cipher = CIPHER_3DES;
2069                 else if (IsDlgButtonChecked (hwnd, IDC_CIPHERBLOWF))
2070                     cfg.cipher = CIPHER_BLOWFISH;
2071                 else if (IsDlgButtonChecked (hwnd, IDC_CIPHERDES))
2072                     cfg.cipher = CIPHER_DES;
2073             }
2074             break;
2075           case IDC_SSHPROT1:
2076           case IDC_SSHPROT2:
2077             if (HIWORD(wParam) == BN_CLICKED ||
2078                 HIWORD(wParam) == BN_DOUBLECLICKED) {
2079                 if (IsDlgButtonChecked (hwnd, IDC_SSHPROT1))
2080                     cfg.sshprot = 1;
2081                 else if (IsDlgButtonChecked (hwnd, IDC_SSHPROT2))
2082                     cfg.sshprot = 2;
2083             }
2084             break;
2085           case IDC_AUTHTIS:
2086             if (HIWORD(wParam) == BN_CLICKED ||
2087                 HIWORD(wParam) == BN_DOUBLECLICKED)
2088                 cfg.try_tis_auth = IsDlgButtonChecked (hwnd, IDC_AUTHTIS);
2089             break;
2090           case IDC_PKEDIT:
2091             if (HIWORD(wParam) == EN_CHANGE)
2092                 GetDlgItemText (hwnd, IDC_PKEDIT, cfg.keyfile,
2093                                 sizeof(cfg.keyfile)-1);
2094             break;
2095           case IDC_CMDEDIT:
2096             if (HIWORD(wParam) == EN_CHANGE)
2097                 GetDlgItemText (hwnd, IDC_CMDEDIT, cfg.remote_cmd,
2098                                 sizeof(cfg.remote_cmd)-1);
2099             break;
2100           case IDC_PKBUTTON:
2101             memset(&of, 0, sizeof(of));
2102 #ifdef OPENFILENAME_SIZE_VERSION_400
2103             of.lStructSize = OPENFILENAME_SIZE_VERSION_400;
2104 #else
2105             of.lStructSize = sizeof(of);
2106 #endif
2107             of.hwndOwner = hwnd;
2108             of.lpstrFilter = "All Files\0*\0\0\0";
2109             of.lpstrCustomFilter = NULL;
2110             of.nFilterIndex = 1;
2111             of.lpstrFile = filename; strcpy(filename, cfg.keyfile);
2112             of.nMaxFile = sizeof(filename);
2113             of.lpstrFileTitle = NULL;
2114             of.lpstrInitialDir = NULL;
2115             of.lpstrTitle = "Select Public Key File";
2116             of.Flags = 0;
2117             if (GetOpenFileName(&of)) {
2118                 strcpy(cfg.keyfile, filename);
2119                 SetDlgItemText (hwnd, IDC_PKEDIT, cfg.keyfile);
2120             }
2121             break;
2122           case IDC_MBWINDOWS:
2123           case IDC_MBXTERM:
2124             cfg.mouse_is_xterm = IsDlgButtonChecked (hwnd, IDC_MBXTERM);
2125             break;
2126           case IDC_CCSET:
2127             {
2128                 BOOL ok;
2129                 int i;
2130                 int n = GetDlgItemInt (hwnd, IDC_CCEDIT, &ok, FALSE);
2131
2132                 if (!ok)
2133                     MessageBeep (0);
2134                 else {
2135                     for (i=0; i<256; i++)
2136                         if (SendDlgItemMessage (hwnd, IDC_CCLIST, LB_GETSEL,
2137                                                 i, 0)) {
2138                             char str[100];
2139                             cfg.wordness[i] = n;
2140                             SendDlgItemMessage (hwnd, IDC_CCLIST,
2141                                                 LB_DELETESTRING, i, 0);
2142                             sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
2143                                     (i>=0x21 && i != 0x7F) ? i : ' ',
2144                                     cfg.wordness[i]);
2145                             SendDlgItemMessage (hwnd, IDC_CCLIST,
2146                                                 LB_INSERTSTRING, i,
2147                                                 (LPARAM)str);
2148                         }
2149                 }
2150             }
2151             break;
2152           case IDC_BOLDCOLOUR:
2153             if (HIWORD(wParam) == BN_CLICKED ||
2154                 HIWORD(wParam) == BN_DOUBLECLICKED) {
2155                 int n, i;
2156                 cfg.bold_colour = IsDlgButtonChecked (hwnd, IDC_BOLDCOLOUR);
2157                 n = SendDlgItemMessage (hwnd, IDC_LIST, LB_GETCOUNT, 0, 0);
2158                 if (cfg.bold_colour && n!=22) {
2159                     for (i=0; i<22; i++)
2160                         if (!permcolour[i])
2161                             SendDlgItemMessage (hwnd, IDC_LIST,
2162                                                 LB_INSERTSTRING, i,
2163                                                 (LPARAM) colours[i]);
2164                 } else if (!cfg.bold_colour && n!=12) {
2165                     for (i=22; i-- ;)
2166                         if (!permcolour[i])
2167                             SendDlgItemMessage (hwnd, IDC_LIST,
2168                                                 LB_DELETESTRING, i, 0);
2169                 }
2170             }
2171             break;
2172           case IDC_PALETTE:
2173             if (HIWORD(wParam) == BN_CLICKED ||
2174                 HIWORD(wParam) == BN_DOUBLECLICKED)
2175                 cfg.try_palette = IsDlgButtonChecked (hwnd, IDC_PALETTE);
2176             break;
2177           case IDC_LIST:
2178             if (HIWORD(wParam) == LBN_DBLCLK ||
2179                 HIWORD(wParam) == LBN_SELCHANGE) {
2180                 int i = SendDlgItemMessage (hwnd, IDC_LIST, LB_GETCURSEL,
2181                                             0, 0);
2182                 if (!cfg.bold_colour)
2183                     i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
2184                 SetDlgItemInt (hwnd, IDC_RVALUE, cfg.colours[i][0], FALSE);
2185                 SetDlgItemInt (hwnd, IDC_GVALUE, cfg.colours[i][1], FALSE);
2186                 SetDlgItemInt (hwnd, IDC_BVALUE, cfg.colours[i][2], FALSE);
2187             }
2188             break;
2189           case IDC_CHANGE:
2190             if (HIWORD(wParam) == BN_CLICKED ||
2191                 HIWORD(wParam) == BN_DOUBLECLICKED) {
2192                 static CHOOSECOLOR cc;
2193                 static DWORD custom[16] = {0};   /* zero initialisers */
2194                 int i = SendDlgItemMessage (hwnd, IDC_LIST, LB_GETCURSEL,
2195                                             0, 0);
2196                 if (!cfg.bold_colour)
2197                     i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
2198                 cc.lStructSize = sizeof(cc);
2199                 cc.hwndOwner = hwnd;
2200                 cc.hInstance = (HWND)hinst;
2201                 cc.lpCustColors = custom;
2202                 cc.rgbResult = RGB (cfg.colours[i][0], cfg.colours[i][1],
2203                                     cfg.colours[i][2]);
2204                 cc.Flags = CC_FULLOPEN | CC_RGBINIT;
2205                 if (ChooseColor(&cc)) {
2206                     cfg.colours[i][0] =
2207                         (unsigned char) (cc.rgbResult & 0xFF);
2208                     cfg.colours[i][1] =
2209                         (unsigned char) (cc.rgbResult >> 8) & 0xFF;
2210                     cfg.colours[i][2] =
2211                         (unsigned char) (cc.rgbResult >> 16) & 0xFF;
2212                     SetDlgItemInt (hwnd, IDC_RVALUE, cfg.colours[i][0],
2213                                    FALSE);
2214                     SetDlgItemInt (hwnd, IDC_GVALUE, cfg.colours[i][1],
2215                                    FALSE);
2216                     SetDlgItemInt (hwnd, IDC_BVALUE, cfg.colours[i][2],
2217                                    FALSE);
2218                 }
2219             }
2220             break;
2221           case IDC_NOXLAT:
2222           case IDC_KOI8WIN1251:
2223           case IDC_88592WIN1250:
2224             cfg.xlat_enablekoiwin =
2225                 IsDlgButtonChecked (hwnd, IDC_KOI8WIN1251);
2226             cfg.xlat_88592w1250 =
2227                 IsDlgButtonChecked (hwnd, IDC_88592WIN1250);
2228             break;
2229           case IDC_CAPSLOCKCYR:
2230             if (HIWORD(wParam) == BN_CLICKED ||
2231                 HIWORD(wParam) == BN_DOUBLECLICKED) {
2232                 cfg.xlat_capslockcyr =
2233                     IsDlgButtonChecked (hwnd, IDC_CAPSLOCKCYR);
2234             }
2235             break;
2236           case IDC_VTXWINDOWS:
2237           case IDC_VTOEMANSI:
2238           case IDC_VTOEMONLY:
2239           case IDC_VTPOORMAN:
2240             cfg.vtmode =
2241                 (IsDlgButtonChecked (hwnd, IDC_VTXWINDOWS) ? VT_XWINDOWS :
2242                  IsDlgButtonChecked (hwnd, IDC_VTOEMANSI) ? VT_OEMANSI :
2243                  IsDlgButtonChecked (hwnd, IDC_VTOEMONLY) ? VT_OEMONLY :
2244                  VT_POORMAN);
2245             break;
2246         }
2247         return 0;
2248       case WM_CLOSE:
2249         EndDialog (hwnd, 0);
2250         return 0;
2251
2252         /* Grrr Explorer will maximize Dialogs! */
2253       case WM_SIZE:
2254         if (wParam == SIZE_MAXIMIZED)
2255            force_normal(hwnd);
2256         return 0;
2257     }
2258     return 0;
2259 }
2260
2261 static int CALLBACK MainDlgProc (HWND hwnd, UINT msg,
2262                                  WPARAM wParam, LPARAM lParam) {
2263     static HWND page = NULL;
2264
2265     if (msg == WM_COMMAND && LOWORD(wParam) == IDOK) {
2266     }
2267     if (msg == WM_COMMAND && LOWORD(wParam) == IDCX_ABOUT) {
2268         EnableWindow(hwnd, 0);
2269         DialogBox(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
2270                   GetParent(hwnd), AboutProc);
2271         EnableWindow(hwnd, 1);
2272         SetActiveWindow(hwnd);
2273     }
2274     return GenericMainDlgProc (hwnd, msg, wParam, lParam, 0);
2275 }
2276
2277 static int CALLBACK ReconfDlgProc (HWND hwnd, UINT msg,
2278                                    WPARAM wParam, LPARAM lParam) {
2279     static HWND page;
2280     return GenericMainDlgProc (hwnd, msg, wParam, lParam, 1);
2281 }
2282
2283 int do_config (void) {
2284     int ret;
2285
2286     get_sesslist(TRUE);
2287     savedsession[0] = '\0';
2288     ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_MAINBOX), NULL, MainDlgProc);
2289     get_sesslist(FALSE);
2290
2291     return ret;
2292 }
2293
2294 int do_reconfig (HWND hwnd) {
2295     Config backup_cfg;
2296     int ret;
2297
2298     backup_cfg = cfg;                  /* structure copy */
2299     ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_RECONF), hwnd, ReconfDlgProc);
2300     if (!ret)
2301         cfg = backup_cfg;              /* structure copy */
2302     else
2303         force_normal(hwnd);
2304
2305     return ret;
2306 }
2307
2308 void logevent (char *string) {
2309     if (nevents >= negsize) {
2310         negsize += 64;
2311         events = srealloc (events, negsize * sizeof(*events));
2312     }
2313     events[nevents] = smalloc(1+strlen(string));
2314     strcpy (events[nevents], string);
2315     nevents++;
2316     if (logbox) {
2317         int count;
2318         SendDlgItemMessage (logbox, IDN_LIST, LB_ADDSTRING,
2319                             0, (LPARAM)string);
2320         count = SendDlgItemMessage (logbox, IDN_LIST, LB_GETCOUNT, 0, 0);
2321         SendDlgItemMessage (logbox, IDN_LIST, LB_SETTOPINDEX, count-1, 0);
2322     }
2323 }
2324
2325 void showeventlog (HWND hwnd) {
2326     if (!logbox) {
2327         logbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_LOGBOX),
2328                                hwnd, LogProc);
2329         ShowWindow (logbox, SW_SHOWNORMAL);
2330     }
2331 }
2332
2333 void showabout (HWND hwnd) {
2334     if (!abtbox) {
2335         abtbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
2336                                hwnd, AboutProc);
2337         ShowWindow (abtbox, SW_SHOWNORMAL);
2338     }
2339 }
2340
2341 void verify_ssh_host_key(char *host, int port, char *keytype,
2342                          char *keystr, char *fingerprint) {
2343     int ret;
2344
2345     static const char absentmsg[] =
2346         "The server's host key is not cached in the registry. You\n"
2347         "have no guarantee that the server is the computer you\n"
2348         "think it is.\n"
2349         "The server's key fingerprint is:\n"
2350         "%s\n"
2351         "If you trust this host, hit Yes to add the key to\n"
2352         "PuTTY's cache and carry on connecting.\n"
2353         "If you do not trust this host, hit No to abandon the\n"
2354         "connection.\n";
2355
2356     static const char wrongmsg[] =
2357         "WARNING - POTENTIAL SECURITY BREACH!\n"
2358         "\n"
2359         "The server's host key does not match the one PuTTY has\n"
2360         "cached in the registry. This means that either the\n"
2361         "server administrator has changed the host key, or you\n"
2362         "have actually connected to another computer pretending\n"
2363         "to be the server.\n"
2364         "The new key fingerprint is:\n"
2365         "%s\n"
2366         "If you were expecting this change and trust the new key,\n"
2367         "hit Yes to update PuTTY's cache and continue connecting.\n"
2368         "If you want to carry on connecting but without updating\n"
2369         "the cache, hit No.\n"
2370         "If you want to abandon the connection completely, hit\n"
2371         "Cancel. Hitting Cancel is the ONLY guaranteed safe\n"
2372         "choice.\n";
2373
2374     static const char mbtitle[] = "PuTTY Security Alert";
2375
2376     
2377     char message[160+                  /* sensible fingerprint max size */
2378                  (sizeof(absentmsg) > sizeof(wrongmsg) ?
2379                   sizeof(absentmsg) : sizeof(wrongmsg))];
2380
2381     /*
2382      * Verify the key against the registry.
2383      */
2384     ret = verify_host_key(host, port, keytype, keystr);
2385
2386     if (ret == 0)                      /* success - key matched OK */
2387         return;
2388     if (ret == 2) {                    /* key was different */
2389         int mbret;
2390         sprintf(message, wrongmsg, fingerprint);
2391         mbret = MessageBox(NULL, message, mbtitle,
2392                            MB_ICONWARNING | MB_YESNOCANCEL);
2393         if (mbret == IDYES)
2394             store_host_key(host, port, keytype, keystr);
2395         if (mbret == IDCANCEL)
2396             exit(0);
2397     }
2398     if (ret == 1) {                    /* key was absent */
2399         int mbret;
2400         sprintf(message, absentmsg, fingerprint);
2401         mbret = MessageBox(NULL, message, mbtitle,
2402                            MB_ICONWARNING | MB_YESNO);
2403         if (mbret == IDNO)
2404             exit(0);
2405         store_host_key(host, port, keytype, keystr);
2406     }
2407 }