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