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