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