]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - windlg.c
575642b9988a6dd67d49035dc566847128daf4e7
[PuTTY.git] / windlg.c
1 #include <windows.h>
2 #include <commctrl.h>
3 #include <commdlg.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6
7 #include "ssh.h"
8 #include "putty.h"
9 #include "winstuff.h"
10 #include "win_res.h"
11 #include "storage.h"
12
13 static char **events = NULL;
14 static int nevents = 0, negsize = 0;
15
16 static HWND logbox = NULL, abtbox = NULL;
17
18 static int readytogo;
19
20 static void force_normal(HWND hwnd)
21 {
22     static int recurse = 0;
23
24     WINDOWPLACEMENT wp;
25
26     if(recurse) return;
27     recurse = 1;
28
29     wp.length = sizeof(wp);
30     if (GetWindowPlacement(hwnd, &wp))
31     {
32         wp.showCmd = SW_SHOWNORMAL;
33         SetWindowPlacement(hwnd, &wp);
34     }
35     recurse = 0;
36 }
37
38 static void MyGetDlgItemInt (HWND hwnd, int id, int *result) {
39     BOOL ok;
40     int n;
41     n = GetDlgItemInt (hwnd, id, &ok, FALSE);
42     if (ok)
43         *result = n;
44 }
45
46 static int CALLBACK LogProc (HWND hwnd, UINT msg,
47                              WPARAM wParam, LPARAM lParam) {
48     int i;
49
50     switch (msg) {
51       case WM_INITDIALOG:
52         for (i=0; i<nevents; i++)
53             SendDlgItemMessage (hwnd, IDN_LIST, LB_ADDSTRING,
54                                 0, (LPARAM)events[i]);
55         return 1;
56       case WM_COMMAND:
57         switch (LOWORD(wParam)) {
58           case IDOK:
59             logbox = NULL;
60             DestroyWindow (hwnd);
61             return 0;
62           case IDN_COPY:
63             if (HIWORD(wParam) == BN_CLICKED ||
64                 HIWORD(wParam) == BN_DOUBLECLICKED) {
65                 int selcount;
66                 int *selitems;
67                 selcount = SendDlgItemMessage(hwnd, IDN_LIST,
68                                               LB_GETSELCOUNT, 0, 0);
69                 selitems = malloc(selcount * sizeof(int));
70                 if (selitems) {
71                     int count = SendDlgItemMessage(hwnd, IDN_LIST,
72                                                    LB_GETSELITEMS,
73                                                    selcount, (LPARAM)selitems);
74                     int i;
75                     int size;
76                     char *clipdata;
77                     static unsigned char sel_nl[] = SEL_NL;
78
79                     if (count == 0) {  /* can't copy zero stuff */
80                         MessageBeep(0);
81                         break;
82                     }
83
84                     size = 0;
85                     for (i = 0; i < count; i++)
86                         size += strlen(events[selitems[i]]) + sizeof(sel_nl);
87
88                     clipdata = malloc(size);
89                     if (clipdata) {
90                         char *p = clipdata;
91                         for (i = 0; i < count; i++) {
92                             char *q = events[selitems[i]];
93                             int qlen = strlen(q);
94                             memcpy(p, q, qlen);
95                             p += qlen;
96                             memcpy(p, sel_nl, sizeof(sel_nl));
97                             p += sizeof(sel_nl);
98                         }
99                         write_clip(clipdata, size, TRUE);
100                         free(clipdata);
101                     }
102                     free(selitems);
103
104                     for (i = 0; i < nevents; i++)
105                         SendDlgItemMessage(hwnd, IDN_LIST, LB_SETSEL,
106                                            FALSE, i);
107                 }
108             }
109             return 0;
110         }
111         return 0;
112       case WM_CLOSE:
113         logbox = NULL;
114         DestroyWindow (hwnd);
115         return 0;
116     }
117     return 0;
118 }
119
120 static int CALLBACK LicenceProc (HWND hwnd, UINT msg,
121                                  WPARAM wParam, LPARAM lParam) {
122     switch (msg) {
123       case WM_INITDIALOG:
124         return 1;
125       case WM_COMMAND:
126         switch (LOWORD(wParam)) {
127           case IDOK:
128             EndDialog(hwnd, 1);
129             return 0;
130         }
131         return 0;
132       case WM_CLOSE:
133         EndDialog(hwnd, 1);
134         return 0;
135     }
136     return 0;
137 }
138
139 static int CALLBACK AboutProc (HWND hwnd, UINT msg,
140                                WPARAM wParam, LPARAM lParam) {
141     switch (msg) {
142       case WM_INITDIALOG:
143         SetDlgItemText (hwnd, IDA_VERSION, ver);
144         return 1;
145       case WM_COMMAND:
146         switch (LOWORD(wParam)) {
147           case IDOK:
148             abtbox = NULL;
149             DestroyWindow (hwnd);
150             return 0;
151           case IDA_LICENCE:
152             EnableWindow(hwnd, 0);
153             DialogBox (hinst, MAKEINTRESOURCE(IDD_LICENCEBOX),
154                        NULL, LicenceProc);
155             EnableWindow(hwnd, 1);
156             SetActiveWindow(hwnd);
157             return 0;
158         }
159         return 0;
160       case WM_CLOSE:
161         abtbox = NULL;
162         DestroyWindow (hwnd);
163         return 0;
164     }
165     return 0;
166 }
167
168 /*
169  * Null dialog procedure.
170  */
171 static int CALLBACK NullDlgProc (HWND hwnd, UINT msg,
172                                  WPARAM wParam, LPARAM lParam) {
173     return 0;
174 }
175
176 static char savedsession[2048];
177
178 enum { IDCX_ABOUT = IDC_ABOUT, IDCX_TVSTATIC, IDCX_TREEVIEW, controlstartvalue,
179
180     sessionpanelstart,
181     IDC_TITLE_SESSION,
182     IDC_BOX_SESSION1, IDC_BOXT_SESSION1,
183     IDC_BOX_SESSION2, IDC_BOXT_SESSION2,
184     IDC_BOX_SESSION3,
185     IDC_HOSTSTATIC,
186     IDC_HOST,
187     IDC_PORTSTATIC,
188     IDC_PORT,
189     IDC_PROTSTATIC,
190     IDC_PROTRAW,
191     IDC_PROTTELNET,
192     IDC_PROTSSH,
193     IDC_SESSSTATIC,
194     IDC_SESSEDIT,
195     IDC_SESSLIST,
196     IDC_SESSLOAD,
197     IDC_SESSSAVE,
198     IDC_SESSDEL,
199     IDC_CLOSEEXIT,
200     sessionpanelend,
201
202     keyboardpanelstart,
203     IDC_TITLE_KEYBOARD,
204     IDC_BOX_KEYBOARD1, IDC_BOXT_KEYBOARD1,
205     IDC_BOX_KEYBOARD2, IDC_BOXT_KEYBOARD2,
206     IDC_BOX_KEYBOARD3, IDC_BOXT_KEYBOARD3,
207     IDC_DELSTATIC,
208     IDC_DEL008,
209     IDC_DEL127,
210     IDC_HOMESTATIC,
211     IDC_HOMETILDE,
212     IDC_HOMERXVT,
213     IDC_FUNCSTATIC,
214     IDC_FUNCTILDE,
215     IDC_FUNCLINUX,
216     IDC_FUNCXTERM,
217     IDC_FUNCVT400,
218     IDC_KPSTATIC,
219     IDC_KPNORMAL,
220     IDC_KPAPPLIC,
221     IDC_KPNH,
222     IDC_NOAPPLICK,
223     IDC_NOAPPLICC,
224     IDC_CURSTATIC,
225     IDC_CURNORMAL,
226     IDC_CURAPPLIC,
227     IDC_COMPOSEKEY,
228     keyboardpanelend,
229
230     terminalpanelstart,
231     IDC_TITLE_TERMINAL,
232     IDC_BOX_TERMINAL1, IDC_BOXT_TERMINAL1,
233     IDC_WRAPMODE,
234     IDC_DECOM,
235     IDC_LFHASCR,
236     IDC_BEEP,
237     IDC_BCE,
238     IDC_BLINKTEXT,
239     IDC_LDISCTERM,
240     terminalpanelend,
241
242     windowpanelstart,
243     IDC_TITLE_WINDOW,
244     IDC_BOX_WINDOW1, IDC_BOXT_WINDOW1,
245     IDC_BOX_WINDOW2, IDC_BOXT_WINDOW2,
246     IDC_BOX_WINDOW3,
247     IDC_ROWSSTATIC,
248     IDC_ROWSEDIT,
249     IDC_COLSSTATIC,
250     IDC_COLSEDIT,
251     IDC_LOCKSIZE,
252     IDC_SCROLLBAR,
253     IDC_CLOSEWARN,
254     IDC_SAVESTATIC,
255     IDC_SAVEEDIT,
256     IDC_ALTF4,
257     IDC_ALTSPACE,
258     IDC_ALTONLY,
259     IDC_SCROLLKEY,
260     IDC_SCROLLDISP,
261     IDC_ALWAYSONTOP,
262     windowpanelend,
263
264     appearancepanelstart,
265     IDC_TITLE_APPEARANCE,
266     IDC_BOX_APPEARANCE1, IDC_BOXT_APPEARANCE1,
267     IDC_BOX_APPEARANCE2, IDC_BOXT_APPEARANCE2,
268     IDC_BOX_APPEARANCE3, IDC_BOXT_APPEARANCE3,
269     IDC_BLINKCUR,
270     IDC_FONTSTATIC,
271     IDC_CHOOSEFONT,
272     IDC_WINTITLE,
273     IDC_WINEDIT,
274     IDC_WINNAME,
275     appearancepanelend,
276
277     connectionpanelstart,
278     IDC_TITLE_CONNECTION,
279     IDC_BOX_CONNECTION1, IDC_BOXT_CONNECTION1,
280     IDC_BOX_CONNECTION2, IDC_BOXT_CONNECTION2,
281     IDC_TTSTATIC,
282     IDC_TTEDIT,
283     IDC_LOGSTATIC,
284     IDC_LOGEDIT,
285     IDC_PINGSTATIC,
286     IDC_PINGEDIT,
287     connectionpanelend,
288
289     telnetpanelstart,
290     IDC_TITLE_TELNET,
291     IDC_BOX_TELNET1, IDC_BOXT_TELNET1,
292     IDC_BOX_TELNET2, IDC_BOXT_TELNET2,
293     IDC_TSSTATIC,
294     IDC_TSEDIT,
295     IDC_ENVSTATIC,
296     IDC_VARSTATIC,
297     IDC_VAREDIT,
298     IDC_VALSTATIC,
299     IDC_VALEDIT,
300     IDC_ENVLIST,
301     IDC_ENVADD,
302     IDC_ENVREMOVE,
303     IDC_EMSTATIC,
304     IDC_EMBSD,
305     IDC_EMRFC,
306     telnetpanelend,
307
308     sshpanelstart,
309     IDC_TITLE_SSH,
310     IDC_BOX_SSH1, IDC_BOXT_SSH1,
311     IDC_BOX_SSH2, IDC_BOXT_SSH2,
312     IDC_BOX_SSH3, IDC_BOXT_SSH3,
313     IDC_NOPTY,
314     IDC_CIPHERSTATIC,
315     IDC_CIPHER3DES,
316     IDC_CIPHERBLOWF,
317     IDC_CIPHERDES,
318     IDC_BUGGYMAC,
319     IDC_AUTHTIS,
320     IDC_PKSTATIC,
321     IDC_PKEDIT,
322     IDC_PKBUTTON,
323     IDC_SSHPROTSTATIC,
324     IDC_SSHPROT1,
325     IDC_SSHPROT2,
326     IDC_AGENTFWD,
327     IDC_CMDSTATIC,
328     IDC_CMDEDIT,
329     IDC_COMPRESS,
330     sshpanelend,
331
332     selectionpanelstart,
333     IDC_TITLE_SELECTION,
334     IDC_BOX_SELECTION1, IDC_BOXT_SELECTION1,
335     IDC_BOX_SELECTION2, IDC_BOXT_SELECTION2,
336     IDC_MBSTATIC,
337     IDC_MBWINDOWS,
338     IDC_MBXTERM,
339     IDC_CCSTATIC,
340     IDC_CCLIST,
341     IDC_CCSET,
342     IDC_CCSTATIC2,
343     IDC_CCEDIT,
344     selectionpanelend,
345
346     colourspanelstart,
347     IDC_TITLE_COLOURS,
348     IDC_BOX_COLOURS1, IDC_BOXT_COLOURS1,
349     IDC_BOX_COLOURS2, IDC_BOXT_COLOURS2,
350     IDC_BOLDCOLOUR,
351     IDC_PALETTE,
352     IDC_COLOURSTATIC,
353     IDC_COLOURLIST,
354     IDC_RSTATIC,
355     IDC_GSTATIC,
356     IDC_BSTATIC,
357     IDC_RVALUE,
358     IDC_GVALUE,
359     IDC_BVALUE,
360     IDC_CHANGE,
361     colourspanelend,
362
363     translationpanelstart,
364     IDC_TITLE_TRANSLATION,
365     IDC_BOX_TRANSLATION1, IDC_BOXT_TRANSLATION1,
366     IDC_BOX_TRANSLATION2, IDC_BOXT_TRANSLATION2,
367     IDC_BOX_TRANSLATION3, IDC_BOXT_TRANSLATION3,
368     IDC_XLATSTATIC,
369     IDC_NOXLAT,
370     IDC_KOI8WIN1251,
371     IDC_88592WIN1250,
372     IDC_88592CP852,
373     IDC_CAPSLOCKCYR,
374     IDC_VTSTATIC,
375     IDC_VTXWINDOWS,
376     IDC_VTOEMANSI,
377     IDC_VTOEMONLY,
378     IDC_VTPOORMAN,
379     translationpanelend,
380
381     controlendvalue
382 };
383
384 static const char *const colours[] = {
385     "Default Foreground", "Default Bold Foreground",
386     "Default Background", "Default Bold Background",
387     "Cursor Text", "Cursor Colour",
388     "ANSI Black", "ANSI Black Bold",
389     "ANSI Red", "ANSI Red Bold",
390     "ANSI Green", "ANSI Green Bold",
391     "ANSI Yellow", "ANSI Yellow Bold",
392     "ANSI Blue", "ANSI Blue Bold",
393     "ANSI Magenta", "ANSI Magenta Bold",
394     "ANSI Cyan", "ANSI Cyan Bold",
395     "ANSI White", "ANSI White Bold"
396 };
397 static const int permcolour[] = {
398     TRUE, FALSE, TRUE, FALSE, TRUE, TRUE,
399     TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE,
400     TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE
401 };
402
403 static void fmtfont (char *buf) {
404     sprintf (buf, "Font: %s, ", cfg.font);
405     if (cfg.fontisbold)
406         strcat(buf, "bold, ");
407     if (cfg.fontheight == 0)
408         strcat (buf, "default height");
409     else
410         sprintf (buf+strlen(buf), "%d-%s",
411                  (cfg.fontheight < 0 ? -cfg.fontheight : cfg.fontheight),
412                  (cfg.fontheight < 0 ? "pixel" : "point"));
413 }
414
415 static void init_dlg_ctrls(HWND hwnd) {
416     int i;
417     char fontstatic[256];
418
419     SetDlgItemText (hwnd, IDC_HOST, cfg.host);
420     SetDlgItemText (hwnd, IDC_SESSEDIT, savedsession);
421     SetDlgItemInt (hwnd, IDC_PORT, cfg.port, FALSE);
422     CheckRadioButton (hwnd, IDC_PROTRAW, IDC_PROTSSH,
423                       cfg.protocol==PROT_SSH ? IDC_PROTSSH :
424                       cfg.protocol==PROT_TELNET ? IDC_PROTTELNET : IDC_PROTRAW );
425     SetDlgItemInt (hwnd, IDC_PINGEDIT, cfg.ping_interval, FALSE);
426
427     CheckRadioButton (hwnd, IDC_DEL008, IDC_DEL127,
428                       cfg.bksp_is_delete ? IDC_DEL127 : IDC_DEL008);
429     CheckRadioButton (hwnd, IDC_HOMETILDE, IDC_HOMERXVT,
430                       cfg.rxvt_homeend ? IDC_HOMERXVT : IDC_HOMETILDE);
431     CheckRadioButton (hwnd, IDC_FUNCTILDE, IDC_FUNCVT400,
432                       cfg.funky_type == 0 ? IDC_FUNCTILDE :
433                       cfg.funky_type == 1 ? IDC_FUNCLINUX :
434                       cfg.funky_type == 2 ? IDC_FUNCXTERM :
435                       cfg.funky_type == 3 ? IDC_FUNCVT400 :
436                       IDC_FUNCTILDE );
437     CheckDlgButton (hwnd, IDC_NOAPPLICC, cfg.no_applic_c);
438     CheckDlgButton (hwnd, IDC_NOAPPLICK, cfg.no_applic_k);
439     CheckRadioButton (hwnd, IDC_CURNORMAL, IDC_CURAPPLIC,
440                       cfg.app_cursor ? IDC_CURAPPLIC : IDC_CURNORMAL);
441     CheckRadioButton (hwnd, IDC_KPNORMAL, IDC_KPNH,
442                       cfg.nethack_keypad ? IDC_KPNH :
443                       cfg.app_keypad ? IDC_KPAPPLIC : IDC_KPNORMAL);
444     CheckDlgButton (hwnd, IDC_ALTF4, cfg.alt_f4);
445     CheckDlgButton (hwnd, IDC_ALTSPACE, cfg.alt_space);
446     CheckDlgButton (hwnd, IDC_ALTONLY, cfg.alt_only);
447     CheckDlgButton (hwnd, IDC_COMPOSEKEY, cfg.compose_key);
448     CheckDlgButton (hwnd, IDC_LDISCTERM, cfg.ldisc_term);
449     CheckDlgButton (hwnd, IDC_ALWAYSONTOP, cfg.alwaysontop);
450     CheckDlgButton (hwnd, IDC_SCROLLKEY, cfg.scroll_on_key);
451     CheckDlgButton (hwnd, IDC_SCROLLDISP, cfg.scroll_on_disp);
452
453     CheckDlgButton (hwnd, IDC_WRAPMODE, cfg.wrap_mode);
454     CheckDlgButton (hwnd, IDC_DECOM, cfg.dec_om);
455     CheckDlgButton (hwnd, IDC_LFHASCR, cfg.lfhascr);
456     SetDlgItemInt (hwnd, IDC_ROWSEDIT, cfg.height, FALSE);
457     SetDlgItemInt (hwnd, IDC_COLSEDIT, cfg.width, FALSE);
458     SetDlgItemInt (hwnd, IDC_SAVEEDIT, cfg.savelines, FALSE);
459     fmtfont (fontstatic);
460     SetDlgItemText (hwnd, IDC_FONTSTATIC, fontstatic);
461     CheckDlgButton (hwnd, IDC_BEEP, cfg.beep);
462     CheckDlgButton (hwnd, IDC_BCE, cfg.bce);
463     CheckDlgButton (hwnd, IDC_BLINKTEXT, cfg.blinktext);
464
465     SetDlgItemText (hwnd, IDC_WINEDIT, cfg.wintitle);
466     CheckDlgButton (hwnd, IDC_WINNAME, cfg.win_name_always);
467     CheckDlgButton (hwnd, IDC_BLINKCUR, cfg.blink_cur);
468     CheckDlgButton (hwnd, IDC_SCROLLBAR, cfg.scrollbar);
469     CheckDlgButton (hwnd, IDC_LOCKSIZE, cfg.locksize);
470     CheckDlgButton (hwnd, IDC_CLOSEEXIT, cfg.close_on_exit);
471     CheckDlgButton (hwnd, IDC_CLOSEWARN, cfg.warn_on_close);
472
473     SetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype);
474     SetDlgItemText (hwnd, IDC_TSEDIT, cfg.termspeed);
475     SetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username);
476     {
477         char *p = cfg.environmt;
478         while (*p) {
479             SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_ADDSTRING, 0,
480                                 (LPARAM) p);
481             p += strlen(p)+1;
482         }
483     }
484     CheckRadioButton (hwnd, IDC_EMBSD, IDC_EMRFC,
485                       cfg.rfc_environ ? IDC_EMRFC : IDC_EMBSD);
486
487     SetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype);
488     SetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username);
489     CheckDlgButton (hwnd, IDC_NOPTY, cfg.nopty);
490     CheckDlgButton (hwnd, IDC_COMPRESS, cfg.compression);
491     CheckDlgButton (hwnd, IDC_BUGGYMAC, cfg.buggymac);
492     CheckDlgButton (hwnd, IDC_AGENTFWD, cfg.agentfwd);
493     CheckRadioButton (hwnd, IDC_CIPHER3DES, IDC_CIPHERDES,
494                       cfg.cipher == CIPHER_BLOWFISH ? IDC_CIPHERBLOWF :
495                       cfg.cipher == CIPHER_DES ? IDC_CIPHERDES :
496                       IDC_CIPHER3DES);
497     CheckRadioButton (hwnd, IDC_SSHPROT1, IDC_SSHPROT2,
498                       cfg.sshprot == 1 ? IDC_SSHPROT1 : IDC_SSHPROT2);
499     CheckDlgButton (hwnd, IDC_AUTHTIS, cfg.try_tis_auth);
500     SetDlgItemText (hwnd, IDC_PKEDIT, cfg.keyfile);
501     SetDlgItemText (hwnd, IDC_CMDEDIT, cfg.remote_cmd);
502
503     CheckRadioButton (hwnd, IDC_MBWINDOWS, IDC_MBXTERM,
504                       cfg.mouse_is_xterm ? IDC_MBXTERM : IDC_MBWINDOWS);
505     {
506         static int tabs[4] = {25, 61, 96, 128};
507         SendDlgItemMessage (hwnd, IDC_CCLIST, LB_SETTABSTOPS, 4,
508                             (LPARAM) tabs);
509     }
510     for (i=0; i<256; i++) {
511         char str[100];
512         sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
513                 (i>=0x21 && i != 0x7F) ? i : ' ',
514                 cfg.wordness[i]);
515         SendDlgItemMessage (hwnd, IDC_CCLIST, LB_ADDSTRING, 0,
516                             (LPARAM) str);
517     }
518
519     CheckDlgButton (hwnd, IDC_BOLDCOLOUR, cfg.bold_colour);
520     CheckDlgButton (hwnd, IDC_PALETTE, cfg.try_palette);
521     {
522         int i;
523         for (i=0; i<22; i++)
524             if (cfg.bold_colour || permcolour[i])
525                 SendDlgItemMessage (hwnd, IDC_COLOURLIST, LB_ADDSTRING, 0,
526                                     (LPARAM) colours[i]);
527     }
528     SendDlgItemMessage (hwnd, IDC_COLOURLIST, LB_SETCURSEL, 0, 0);
529     SetDlgItemInt (hwnd, IDC_RVALUE, cfg.colours[0][0], FALSE);
530     SetDlgItemInt (hwnd, IDC_GVALUE, cfg.colours[0][1], FALSE);
531     SetDlgItemInt (hwnd, IDC_BVALUE, cfg.colours[0][2], FALSE);
532
533     CheckRadioButton (hwnd, IDC_NOXLAT, IDC_88592CP852,
534                       cfg.xlat_88592w1250 ? IDC_88592WIN1250 :
535                       cfg.xlat_88592cp852 ? IDC_88592CP852 :
536                       cfg.xlat_enablekoiwin ? IDC_KOI8WIN1251 :
537                       IDC_NOXLAT);
538     CheckDlgButton (hwnd, IDC_CAPSLOCKCYR, cfg.xlat_capslockcyr);
539     CheckRadioButton (hwnd, IDC_VTXWINDOWS, IDC_VTPOORMAN,
540                       cfg.vtmode == VT_XWINDOWS ? IDC_VTXWINDOWS :
541                       cfg.vtmode == VT_OEMANSI ? IDC_VTOEMANSI :
542                       cfg.vtmode == VT_OEMONLY ? IDC_VTOEMONLY :
543                       IDC_VTPOORMAN);
544 }
545
546 static void hide(HWND hwnd, int hide, int minid, int maxid) {
547     int i;
548     for (i = minid; i < maxid; i++) {
549         HWND ctl = GetDlgItem(hwnd, i);
550         if (ctl) {
551             ShowWindow(ctl, hide ? SW_HIDE : SW_SHOW);
552         }
553     }
554 }
555
556 struct treeview_faff {
557     HWND treeview;
558     HTREEITEM lastat[4];
559 };
560
561 static HTREEITEM treeview_insert(struct treeview_faff *faff,
562                                  int level, char *text) {
563     TVINSERTSTRUCT ins;
564     int i;
565     HTREEITEM newitem;
566     ins.hParent = (level > 0 ? faff->lastat[level-1] : TVI_ROOT);
567     ins.hInsertAfter = faff->lastat[level];
568 #if _WIN32_IE >= 0x0400 && defined NONAMELESSUNION
569 #define INSITEM DUMMYUNIONNAME.item
570 #else
571 #define INSITEM item
572 #endif
573     ins.INSITEM.mask = TVIF_TEXT;
574     ins.INSITEM.pszText = text;
575     newitem = TreeView_InsertItem(faff->treeview, &ins);
576     if (level > 0)
577         TreeView_Expand(faff->treeview, faff->lastat[level-1], TVE_EXPAND);
578     faff->lastat[level] = newitem;
579     for (i = level+1; i < 4; i++) faff->lastat[i] = NULL;
580     return newitem;
581 }
582
583 /*
584  * This _huge_ function is the configuration box.
585  */
586 static int GenericMainDlgProc (HWND hwnd, UINT msg,
587                                WPARAM wParam, LPARAM lParam,
588                                int dlgtype) {
589     HWND hw, treeview;
590     struct treeview_faff tvfaff;
591     HTREEITEM hsession;
592     OPENFILENAME of;
593     char filename[sizeof(cfg.keyfile)];
594     CHOOSEFONT cf;
595     LOGFONT lf;
596     char fontstatic[256];
597     int i;
598
599     switch (msg) {
600       case WM_INITDIALOG:
601         readytogo = 0;
602         SetWindowLong(hwnd, GWL_USERDATA, 0);
603         /*
604          * Centre the window.
605          */
606         {                              /* centre the window */
607             RECT rs, rd;
608
609             hw = GetDesktopWindow();
610             if (GetWindowRect (hw, &rs) && GetWindowRect (hwnd, &rd))
611                 MoveWindow (hwnd, (rs.right + rs.left + rd.left - rd.right)/2,
612                             (rs.bottom + rs.top + rd.top - rd.bottom)/2,
613                             rd.right-rd.left, rd.bottom-rd.top, TRUE);
614         }
615
616         /*
617          * Create the tree view.
618          */
619         {
620             RECT r;
621             WPARAM font;
622             HWND tvstatic;
623
624             r.left = 3; r.right = r.left + 75;
625             r.top = 3; r.bottom = r.top + 10;
626             MapDialogRect(hwnd, &r);
627             tvstatic = CreateWindowEx(0, "STATIC", "Cate&gory:",
628                                       WS_CHILD | WS_VISIBLE,
629                                       r.left, r.top,
630                                       r.right-r.left, r.bottom-r.top,
631                                       hwnd, (HMENU)IDCX_TVSTATIC, hinst, NULL);
632             font = SendMessage(hwnd, WM_GETFONT, 0, 0);
633             SendMessage(tvstatic, WM_SETFONT, font, MAKELPARAM(TRUE, 0));
634
635             r.left = 3; r.right = r.left + 75;
636             r.top = 13; r.bottom = r.top + 206;
637             MapDialogRect(hwnd, &r);
638             treeview = CreateWindowEx(WS_EX_CLIENTEDGE, WC_TREEVIEW, "",
639                                       WS_CHILD | WS_VISIBLE |
640                                       WS_TABSTOP | TVS_HASLINES |
641                                       TVS_DISABLEDRAGDROP | TVS_HASBUTTONS |
642                                       TVS_LINESATROOT | TVS_SHOWSELALWAYS,
643                                       r.left, r.top,
644                                       r.right-r.left, r.bottom-r.top,
645                                       hwnd, (HMENU)IDCX_TREEVIEW, hinst, NULL);
646             font = SendMessage(hwnd, WM_GETFONT, 0, 0);
647             SendMessage(treeview, WM_SETFONT, font, MAKELPARAM(TRUE, 0));
648             tvfaff.treeview = treeview;
649             memset(tvfaff.lastat, 0, sizeof(tvfaff.lastat));
650         }
651
652         /*
653          * Create the various panelfuls of controls.
654          */
655
656         /* The Session panel. Accelerators used: [acgo] nprthelsdx */
657         {
658             struct ctlpos cp;
659             ctlposinit(&cp, hwnd, 80, 3, 13);
660             bartitle(&cp, "Basic options for your PuTTY session",
661                      IDC_TITLE_SESSION);
662             if (dlgtype == 0) {
663                 beginbox(&cp, "Specify your connection by host name",
664                          IDC_BOX_SESSION1, IDC_BOXT_SESSION1);
665                 multiedit(&cp,
666                           "Host &Name", IDC_HOSTSTATIC, IDC_HOST, 75,
667                           "&Port", IDC_PORTSTATIC, IDC_PORT, 25, NULL);
668                 if (backends[2].backend == NULL) {
669                     /* this is PuTTYtel, so only two protocols available */
670                     radioline(&cp, "Protocol:", IDC_PROTSTATIC, 3,
671                               "&Raw", IDC_PROTRAW,
672                               "&Telnet", IDC_PROTTELNET, NULL);
673                 } else {
674                     radioline(&cp, "Protocol:", IDC_PROTSTATIC, 3,
675                               "&Raw", IDC_PROTRAW,
676                               "&Telnet", IDC_PROTTELNET,
677 #ifdef FWHACK
678                               "SS&H/hack",
679 #else
680                               "SS&H",
681 #endif
682                               IDC_PROTSSH, NULL);
683                 }
684                 endbox(&cp);
685                 beginbox(&cp, "Load, save or delete a stored session",
686                          IDC_BOX_SESSION2, IDC_BOXT_SESSION2);
687                 sesssaver(&cp, "Sav&ed Sessions",
688                           IDC_SESSSTATIC, IDC_SESSEDIT, IDC_SESSLIST,
689                           "&Load", IDC_SESSLOAD,
690                           "&Save", IDC_SESSSAVE,
691                           "&Delete", IDC_SESSDEL, NULL);
692                 endbox(&cp);
693             }
694             beginbox(&cp, NULL, IDC_BOX_SESSION3, 0);
695             checkbox(&cp, "Close Window on E&xit", IDC_CLOSEEXIT);
696             endbox(&cp);
697
698             hsession = treeview_insert(&tvfaff, 0, "Session");
699         }
700
701         /* The Terminal panel. Accelerators used: [acgo] &dlbenu */
702         {
703             struct ctlpos cp;
704             ctlposinit(&cp, hwnd, 80, 3, 13);
705             bartitle(&cp, "Options controlling the terminal emulation",
706                      IDC_TITLE_TERMINAL);
707             beginbox(&cp, "Set various terminal options",
708                      IDC_BOX_TERMINAL1, IDC_BOXT_TERMINAL1);
709             checkbox(&cp, "Auto &wrap mode initially on", IDC_WRAPMODE);
710             checkbox(&cp, "&DEC Origin Mode initially on", IDC_DECOM);
711             checkbox(&cp, "Implicit CR in every &LF", IDC_LFHASCR);
712             checkbox(&cp, "&Beep enabled", IDC_BEEP);
713             checkbox(&cp, "Use background colour to &erase screen", IDC_BCE);
714             checkbox(&cp, "Enable bli&nking text", IDC_BLINKTEXT);
715             checkbox(&cp, "&Use local terminal line discipline", IDC_LDISCTERM);
716             endbox(&cp);
717
718             treeview_insert(&tvfaff, 0, "Terminal");
719         }
720
721         /* The Keyboard panel. Accelerators used: [acgo] h?srvlxvnpmietu */
722         {
723             struct ctlpos cp;
724             ctlposinit(&cp, hwnd, 80, 3, 13);
725             bartitle(&cp, "Options controlling the effects of keys",
726                      IDC_TITLE_KEYBOARD);
727             beginbox(&cp, "Change the sequences sent by:",
728                      IDC_BOX_KEYBOARD1, IDC_BOXT_KEYBOARD1);
729             radioline(&cp, "The Backspace key", IDC_DELSTATIC, 2,
730                       "Control-&H", IDC_DEL008,
731                       "Control-&? (127)", IDC_DEL127, NULL);
732             radioline(&cp, "The Home and End keys", IDC_HOMESTATIC, 2,
733                       "&Standard", IDC_HOMETILDE,
734                       "&rxvt", IDC_HOMERXVT, NULL);
735             radioline(&cp, "The Function keys and keypad", IDC_FUNCSTATIC, 4,
736                       "ESC[n&~", IDC_FUNCTILDE,
737                       "&Linux", IDC_FUNCLINUX,
738                       "&Xterm R6", IDC_FUNCXTERM,
739                       "&VT400", IDC_FUNCVT400, NULL);
740             endbox(&cp);
741             beginbox(&cp, "Application keypad settings:",
742                      IDC_BOX_KEYBOARD2, IDC_BOXT_KEYBOARD2);
743             checkbox(&cp,
744                      "Application c&ursor keys totally disabled",
745                      IDC_NOAPPLICC);
746             radioline(&cp, "Initial state of cursor keys:", IDC_CURSTATIC, 2,
747                       "&Normal", IDC_CURNORMAL,
748                       "A&pplication", IDC_CURAPPLIC, NULL);
749             checkbox(&cp,
750                      "Application ke&ypad keys totally disabled",
751                      IDC_NOAPPLICK);
752             radioline(&cp, "Initial state of numeric keypad:", IDC_KPSTATIC, 3,
753                       "Nor&mal", IDC_KPNORMAL,
754                       "Appl&ication", IDC_KPAPPLIC,
755                       "N&etHack", IDC_KPNH, NULL);
756             endbox(&cp);
757             beginbox(&cp, "Enable extra keyboard features:",
758                      IDC_BOX_KEYBOARD3, IDC_BOXT_KEYBOARD3);
759             checkbox(&cp, "Application and AltGr ac&t as Compose key",
760                      IDC_COMPOSEKEY);
761             endbox(&cp);
762
763             treeview_insert(&tvfaff, 1, "Keyboard");
764         }
765
766         /* The Window panel. Accelerators used: [acgo] bsdkw4ylpt */
767         {
768             struct ctlpos cp;
769             ctlposinit(&cp, hwnd, 80, 3, 13);
770             bartitle(&cp, "Options controlling PuTTY's window",
771                      IDC_TITLE_WINDOW);
772             beginbox(&cp, "Set the size of the window",
773                      IDC_BOX_WINDOW1, IDC_BOXT_WINDOW1);
774             multiedit(&cp,
775                       "&Rows", IDC_ROWSSTATIC, IDC_ROWSEDIT, 50,
776                       "Colu&mns", IDC_COLSSTATIC, IDC_COLSEDIT, 50,
777                       NULL);
778             checkbox(&cp, "Loc&k window size against resizing", IDC_LOCKSIZE);
779             endbox(&cp);
780             beginbox(&cp, "Control the scrollback in the window",
781                      IDC_BOX_WINDOW2, IDC_BOXT_WINDOW2);
782             staticedit(&cp, "Lines of &scrollback",
783                        IDC_SAVESTATIC, IDC_SAVEEDIT, 50);
784             checkbox(&cp, "&Display scrollbar", IDC_SCROLLBAR);
785             checkbox(&cp, "Reset scrollback on &keypress", IDC_SCROLLKEY);
786             checkbox(&cp, "Reset scrollback on dis&play activity",
787                      IDC_SCROLLDISP);
788             endbox(&cp);
789             beginbox(&cp, NULL, IDC_BOX_WINDOW3, 0);
790             checkbox(&cp, "&Warn before closing window", IDC_CLOSEWARN);
791             checkbox(&cp, "Window closes on ALT-F&4", IDC_ALTF4);
792             checkbox(&cp, "S&ystem menu appears on ALT-Space", IDC_ALTSPACE);
793             checkbox(&cp, "System menu appears on A&LT alone", IDC_ALTONLY);
794             checkbox(&cp, "Ensure window is always on &top", IDC_ALWAYSONTOP);
795             endbox(&cp);
796
797             treeview_insert(&tvfaff, 0, "Window");
798         }
799
800         /* The Appearance panel. Accelerators used: [acgo] rmkhti */
801         {
802             struct ctlpos cp;
803             ctlposinit(&cp, hwnd, 80, 3, 13);
804             bartitle(&cp, "Options controlling PuTTY's appearance",
805                      IDC_TITLE_APPEARANCE);
806             beginbox(&cp, "Adjust the use of the cursor",
807                      IDC_BOX_APPEARANCE1, IDC_BOXT_APPEARANCE1);
808             checkbox(&cp, "Cursor &blinks", IDC_BLINKCUR);
809             endbox(&cp);
810             beginbox(&cp, "Set the font used in the terminal window",
811                      IDC_BOX_APPEARANCE2, IDC_BOXT_APPEARANCE2);
812             staticbtn(&cp, "", IDC_FONTSTATIC, "C&hange...", IDC_CHOOSEFONT);
813             endbox(&cp);
814             beginbox(&cp, "Adjust the use of the window title",
815                      IDC_BOX_APPEARANCE3, IDC_BOXT_APPEARANCE3);
816             if (dlgtype == 0)
817                 multiedit(&cp,
818                           "Initial window &title:", IDC_WINTITLE,
819                           IDC_WINEDIT, 100, NULL);
820             checkbox(&cp, "Avoid ever using &icon title", IDC_WINNAME);
821             endbox(&cp);
822
823             treeview_insert(&tvfaff, 1, "Appearance");
824         }
825
826         /* The Translation panel. Accelerators used: [acgo] xbepnkis */
827         {
828             struct ctlpos cp;
829             ctlposinit(&cp, hwnd, 80, 3, 13);
830             bartitle(&cp, "Options controlling character set translation",
831                      IDC_TITLE_TRANSLATION);
832             beginbox(&cp, "Adjust how PuTTY displays line drawing characters",
833                      IDC_BOX_TRANSLATION1, IDC_BOXT_TRANSLATION1);
834             radiobig(&cp,
835                      "Handling of line drawing characters:", IDC_VTSTATIC,
836                      "Font has &XWindows encoding", IDC_VTXWINDOWS,
837                      "Use font in &both ANSI and OEM modes", IDC_VTOEMANSI,
838                      "Use font in O&EM mode only", IDC_VTOEMONLY,
839                      "&Poor man's line drawing (""+"", ""-"" and ""|"")",
840                      IDC_VTPOORMAN, NULL);
841             endbox(&cp);
842             beginbox(&cp, "Enable character set translation on received data",
843                      IDC_BOX_TRANSLATION2, IDC_BOXT_TRANSLATION2);
844             radiobig(&cp,
845                      "Character set translation:", IDC_XLATSTATIC,
846                      "&None", IDC_NOXLAT,
847                      "&KOI8 / Win-1251", IDC_KOI8WIN1251,
848                      "&ISO-8859-2 / Win-1250", IDC_88592WIN1250,
849                      "&ISO-8859-2 / CP852", IDC_88592CP852, NULL);
850             endbox(&cp);
851             beginbox(&cp, "Enable character set translation on input data",
852                      IDC_BOX_TRANSLATION3, IDC_BOXT_TRANSLATION3);
853             checkbox(&cp, "CAP&S LOCK acts as cyrillic switch",
854                      IDC_CAPSLOCKCYR);
855             endbox(&cp);
856
857             treeview_insert(&tvfaff, 1, "Translation");
858         }
859
860         /* The Selection panel. Accelerators used: [acgo] wxst */
861         {
862             struct ctlpos cp;
863             ctlposinit(&cp, hwnd, 80, 3, 13);
864             bartitle(&cp, "Options controlling copy and paste",
865                      IDC_TITLE_SELECTION);
866             beginbox(&cp, "Control which mouse button does which thing",
867                      IDC_BOX_SELECTION1, IDC_BOXT_SELECTION1);
868             radiobig(&cp, "Action of mouse buttons:", IDC_MBSTATIC,
869                      "&Windows (Right pastes, Middle extends)", IDC_MBWINDOWS,
870                      "&xterm (Right extends, Middle pastes)", IDC_MBXTERM,
871                      NULL);
872             endbox(&cp);
873             beginbox(&cp, "Control the select-one-word-at-a-time mode",
874                      IDC_BOX_SELECTION2, IDC_BOXT_SELECTION2);
875             charclass(&cp, "Character classes:", IDC_CCSTATIC, IDC_CCLIST,
876                       "&Set", IDC_CCSET, IDC_CCEDIT,
877                       "&to class", IDC_CCSTATIC2);
878             endbox(&cp);
879
880             treeview_insert(&tvfaff, 1, "Selection");
881         }
882
883         /* The Colours panel. Accelerators used: [acgo] blum */
884         {
885             struct ctlpos cp;
886             ctlposinit(&cp, hwnd, 80, 3, 13);
887             bartitle(&cp, "Options controlling use of colours",
888                      IDC_TITLE_COLOURS);
889             beginbox(&cp, "General options for colour usage",
890                      IDC_BOX_COLOURS1, IDC_BOXT_COLOURS1);
891             checkbox(&cp, "&Bolded text is a different colour", IDC_BOLDCOLOUR);
892             checkbox(&cp, "Attempt to use &logical palettes", IDC_PALETTE);
893             endbox(&cp);
894             beginbox(&cp, "Adjust the precise colours PuTTY displays",
895                      IDC_BOX_COLOURS2, IDC_BOXT_COLOURS2);
896             colouredit(&cp, "Select a colo&ur and then click to modify it:",
897                        IDC_COLOURSTATIC, IDC_COLOURLIST,
898                        "&Modify...", IDC_CHANGE,
899                        "Red:", IDC_RSTATIC, IDC_RVALUE,
900                        "Green:", IDC_GSTATIC, IDC_GVALUE,
901                        "Blue:", IDC_BSTATIC, IDC_BVALUE, NULL);
902             endbox(&cp);
903
904             treeview_insert(&tvfaff, 1, "Colours");
905         }
906
907         /* The Connection panel. Accelerators used: [acgo] tuk */
908         {
909             struct ctlpos cp;
910             ctlposinit(&cp, hwnd, 80, 3, 13);
911             bartitle(&cp, "Options controlling the connection", IDC_TITLE_CONNECTION);
912             if (dlgtype == 0) {
913                 beginbox(&cp, "Data to send to the server",
914                          IDC_BOX_CONNECTION1, IDC_BOXT_CONNECTION1);
915                 staticedit(&cp, "Terminal-&type string", IDC_TTSTATIC, IDC_TTEDIT, 50);
916                 staticedit(&cp, "Auto-login &username", IDC_LOGSTATIC, IDC_LOGEDIT, 50);
917                 endbox(&cp);
918             }
919             beginbox(&cp, "Sending of null packets to keep session active",
920                      IDC_BOX_CONNECTION2, IDC_BOXT_CONNECTION2);
921             staticedit(&cp, "Minutes between &keepalives (0 to turn off)",
922                        IDC_PINGSTATIC, IDC_PINGEDIT, 25);
923             endbox(&cp);
924
925             treeview_insert(&tvfaff, 0, "Connection");
926         }
927
928         /* The Telnet panel. Accelerators used: [acgo] svldrbf */
929         {
930             struct ctlpos cp;
931             ctlposinit(&cp, hwnd, 80, 3, 13);
932             if (dlgtype == 0) {
933                 bartitle(&cp, "Options controlling Telnet connections", IDC_TITLE_TELNET);
934                 beginbox(&cp, "Data to send to the server",
935                          IDC_BOX_TELNET1, IDC_BOXT_TELNET1);
936                 staticedit(&cp, "Terminal-&speed string", IDC_TSSTATIC, IDC_TSEDIT, 50);
937                 envsetter(&cp, "Environment variables:", IDC_ENVSTATIC,
938                           "&Variable", IDC_VARSTATIC, IDC_VAREDIT,
939                           "Va&lue", IDC_VALSTATIC, IDC_VALEDIT,
940                           IDC_ENVLIST,
941                           "A&dd", IDC_ENVADD, "&Remove", IDC_ENVREMOVE);
942                 endbox(&cp);
943                 beginbox(&cp, "Telnet protocol adjustments",
944                          IDC_BOX_TELNET2, IDC_BOXT_TELNET2);
945                 radioline(&cp, "Handling of OLD_ENVIRON ambiguity:", IDC_EMSTATIC, 2,
946                           "&BSD (commonplace)", IDC_EMBSD,
947                           "R&FC 1408 (unusual)", IDC_EMRFC, NULL);
948                 endbox(&cp);
949
950                 treeview_insert(&tvfaff, 1, "Telnet");
951             }
952         }
953
954         /* The SSH panel. Accelerators used: [acgo] rmakwp123bd */
955         if (backends[2].backend != NULL) {
956             struct ctlpos cp;
957             ctlposinit(&cp, hwnd, 80, 3, 13);
958             if (dlgtype == 0) {
959                 bartitle(&cp, "Options controlling SSH connections", IDC_TITLE_SSH);
960                 beginbox(&cp, "Data to send to the server",
961                          IDC_BOX_SSH1, IDC_BOXT_SSH1);
962                 multiedit(&cp,
963                           "&Remote command:", IDC_CMDSTATIC, IDC_CMDEDIT, 100,
964                           NULL);
965                 endbox(&cp);
966                 beginbox(&cp, "Authentication options",
967                          IDC_BOX_SSH2, IDC_BOXT_SSH2);
968                 checkbox(&cp, "Atte&mpt TIS or CryptoCard authentication",
969                          IDC_AUTHTIS);
970                 checkbox(&cp, "Allow &agent forwarding", IDC_AGENTFWD);
971                 editbutton(&cp, "Private &key file for authentication:",
972                            IDC_PKSTATIC, IDC_PKEDIT, "Bro&wse...", IDC_PKBUTTON);
973                 endbox(&cp);
974                 beginbox(&cp, "Protocol options",
975                          IDC_BOX_SSH3, IDC_BOXT_SSH3);
976                 checkbox(&cp, "Don't allocate a &pseudo-terminal", IDC_NOPTY);
977                 checkbox(&cp, "Enable compr&ession", IDC_COMPRESS);
978                 radioline(&cp, "Preferred SSH protocol version:",
979                           IDC_SSHPROTSTATIC, 2,
980                           "&1", IDC_SSHPROT1, "&2", IDC_SSHPROT2, NULL);
981                 radioline(&cp, "Preferred encryption algorithm:", IDC_CIPHERSTATIC, 3,
982                           "&3DES", IDC_CIPHER3DES,
983                           "&Blowfish", IDC_CIPHERBLOWF,
984                           "&DES", IDC_CIPHERDES, NULL);
985                 checkbox(&cp, "Imitate SSH 2 MAC bug in commercial <= v2.3.x",
986                          IDC_BUGGYMAC);
987                 endbox(&cp);
988
989                 treeview_insert(&tvfaff, 1, "SSH");
990             }
991         }
992
993         init_dlg_ctrls(hwnd);
994         for (i = 0; i < nsessions; i++)
995             SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_ADDSTRING,
996                                 0, (LPARAM) (sessions[i]));
997
998         /*
999          * Hide all the controls to start with.
1000          */
1001         hide(hwnd, TRUE, controlstartvalue, controlendvalue);
1002
1003         /*
1004          * Put the treeview selection on to the Session panel. This
1005          * should also cause unhiding of the relevant controls.
1006          */
1007         TreeView_SelectItem(treeview, hsession);
1008
1009         /*
1010          * Set focus into the first available control.
1011          */
1012         {
1013             HWND ctl;
1014             ctl = GetDlgItem(hwnd, IDC_HOST);
1015             if (!ctl) ctl = GetDlgItem(hwnd, IDC_CLOSEEXIT);
1016             SetFocus(ctl);
1017         }
1018
1019         SetWindowLong(hwnd, GWL_USERDATA, 1);
1020         return 0;
1021       case WM_LBUTTONUP:
1022         /*
1023          * Button release should trigger WM_OK if there was a
1024          * previous double click on the session list.
1025          */
1026         ReleaseCapture();
1027         if (readytogo)
1028             SendMessage (hwnd, WM_COMMAND, IDOK, 0);
1029         break;
1030       case WM_NOTIFY:
1031         if (LOWORD(wParam) == IDCX_TREEVIEW &&
1032             ((LPNMHDR)lParam)->code == TVN_SELCHANGED) {
1033             HTREEITEM i = TreeView_GetSelection(((LPNMHDR)lParam)->hwndFrom);
1034             TVITEM item;
1035             char buffer[64];
1036             item.hItem = i;
1037             item.pszText = buffer;
1038             item.cchTextMax = sizeof(buffer);
1039             item.mask = TVIF_TEXT;
1040             TreeView_GetItem(((LPNMHDR)lParam)->hwndFrom, &item);
1041             hide(hwnd, TRUE, controlstartvalue, controlendvalue);
1042             if (!strcmp(buffer, "Session"))
1043                 hide(hwnd, FALSE, sessionpanelstart, sessionpanelend);
1044             if (!strcmp(buffer, "Keyboard"))
1045                 hide(hwnd, FALSE, keyboardpanelstart, keyboardpanelend);
1046             if (!strcmp(buffer, "Terminal"))
1047                 hide(hwnd, FALSE, terminalpanelstart, terminalpanelend);
1048             if (!strcmp(buffer, "Window"))
1049                 hide(hwnd, FALSE, windowpanelstart, windowpanelend);
1050             if (!strcmp(buffer, "Appearance"))
1051                 hide(hwnd, FALSE, appearancepanelstart, appearancepanelend);
1052             if (!strcmp(buffer, "Connection"))
1053                 hide(hwnd, FALSE, connectionpanelstart, connectionpanelend);
1054             if (!strcmp(buffer, "Telnet"))
1055                 hide(hwnd, FALSE, telnetpanelstart, telnetpanelend);
1056             if (!strcmp(buffer, "SSH"))
1057                 hide(hwnd, FALSE, sshpanelstart, sshpanelend);
1058             if (!strcmp(buffer, "Selection"))
1059                 hide(hwnd, FALSE, selectionpanelstart, selectionpanelend);
1060             if (!strcmp(buffer, "Colours"))
1061                 hide(hwnd, FALSE, colourspanelstart, colourspanelend);
1062             if (!strcmp(buffer, "Translation"))
1063                 hide(hwnd, FALSE, translationpanelstart, translationpanelend);
1064
1065             SetFocus (((LPNMHDR)lParam)->hwndFrom);   /* ensure focus stays */
1066             return 0;
1067         }
1068         break;
1069       case WM_COMMAND:
1070         /*
1071          * Only process WM_COMMAND once the dialog is fully formed.
1072          */
1073         if (GetWindowLong(hwnd, GWL_USERDATA) == 1) switch (LOWORD(wParam)) {
1074           case IDOK:
1075             if (*cfg.host)
1076                 EndDialog (hwnd, 1);
1077             else
1078                 MessageBeep (0);
1079             return 0;
1080           case IDCANCEL:
1081             EndDialog (hwnd, 0);
1082             return 0;
1083           case IDC_PROTTELNET:
1084           case IDC_PROTSSH:
1085           case IDC_PROTRAW:
1086             if (HIWORD(wParam) == BN_CLICKED ||
1087                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1088                 int i = IsDlgButtonChecked (hwnd, IDC_PROTSSH);
1089                 int j = IsDlgButtonChecked (hwnd, IDC_PROTTELNET);
1090                 cfg.protocol = i ? PROT_SSH : j ? PROT_TELNET : PROT_RAW ;
1091                 if ((cfg.protocol == PROT_SSH && cfg.port == 23) ||
1092                     (cfg.protocol == PROT_TELNET && cfg.port == 22)) {
1093                     cfg.port = i ? 22 : 23;
1094                     SetDlgItemInt (hwnd, IDC_PORT, cfg.port, FALSE);
1095                 }
1096             }
1097             break;
1098           case IDC_HOST:
1099             if (HIWORD(wParam) == EN_CHANGE)
1100                 GetDlgItemText (hwnd, IDC_HOST, cfg.host,
1101                                 sizeof(cfg.host)-1);
1102             break;
1103           case IDC_PORT:
1104             if (HIWORD(wParam) == EN_CHANGE)
1105                 MyGetDlgItemInt (hwnd, IDC_PORT, &cfg.port);
1106             break;
1107           case IDC_SESSEDIT:
1108             if (HIWORD(wParam) == EN_CHANGE) {
1109                 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL,
1110                                     (WPARAM) -1, 0);
1111                 GetDlgItemText (hwnd, IDC_SESSEDIT,
1112                                 savedsession, sizeof(savedsession)-1);
1113                 savedsession[sizeof(savedsession)-1] = '\0';
1114             }
1115             break;
1116           case IDC_SESSSAVE:
1117             if (HIWORD(wParam) == BN_CLICKED ||
1118                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1119                 /*
1120                  * Save a session
1121                  */
1122                 char str[2048];
1123                 GetDlgItemText (hwnd, IDC_SESSEDIT, str, sizeof(str)-1);
1124                 if (!*str) {
1125                     int n = SendDlgItemMessage (hwnd, IDC_SESSLIST,
1126                                                 LB_GETCURSEL, 0, 0);
1127                     if (n == LB_ERR) {
1128                         MessageBeep(0);
1129                         break;
1130                     }
1131                     strcpy (str, sessions[n]);
1132                 }
1133                 save_settings (str, !!strcmp(str, "Default Settings"), &cfg);
1134                 get_sesslist (FALSE);
1135                 get_sesslist (TRUE);
1136                 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_RESETCONTENT,
1137                                     0, 0);
1138                 for (i = 0; i < nsessions; i++)
1139                     SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_ADDSTRING,
1140                                         0, (LPARAM) (sessions[i]));
1141                 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL,
1142                                     (WPARAM) -1, 0);
1143             }
1144             break;
1145           case IDC_SESSLIST:
1146           case IDC_SESSLOAD:
1147             if (LOWORD(wParam) == IDC_SESSLOAD &&
1148                 HIWORD(wParam) != BN_CLICKED &&
1149                 HIWORD(wParam) != BN_DOUBLECLICKED)
1150                 break;
1151             if (LOWORD(wParam) == IDC_SESSLIST &&
1152                 HIWORD(wParam) != LBN_DBLCLK)
1153                 break;
1154             {
1155                 int n = SendDlgItemMessage (hwnd, IDC_SESSLIST,
1156                                             LB_GETCURSEL, 0, 0);
1157                 int isdef;
1158                 if (n == LB_ERR) {
1159                     MessageBeep(0);
1160                     break;
1161                 }
1162                 isdef = !strcmp(sessions[n], "Default Settings");
1163                 load_settings (sessions[n], !isdef, &cfg);
1164                 init_dlg_ctrls(hwnd);
1165                 if (!isdef)
1166                     SetDlgItemText(hwnd, IDC_SESSEDIT, sessions[n]);
1167             }
1168             if (LOWORD(wParam) == IDC_SESSLIST) {
1169                 /*
1170                  * A double-click on a saved session should
1171                  * actually start the session, not just load it.
1172                  * Unless it's Default Settings or some other
1173                  * host-less set of saved settings.
1174                  */
1175                 if (*cfg.host) {
1176                     readytogo = TRUE;
1177                     SetCapture(hwnd);
1178                 }
1179             }
1180             break;
1181           case IDC_SESSDEL:
1182             if (HIWORD(wParam) == BN_CLICKED ||
1183                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1184                 int n = SendDlgItemMessage (hwnd, IDC_SESSLIST,
1185                                             LB_GETCURSEL, 0, 0);
1186                 if (n == LB_ERR || n == 0) {
1187                     MessageBeep(0);
1188                     break;
1189                 }
1190                 del_settings(sessions[n]);
1191                 get_sesslist (FALSE);
1192                 get_sesslist (TRUE);
1193                 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_RESETCONTENT,
1194                                     0, 0);
1195                 for (i = 0; i < nsessions; i++)
1196                     SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_ADDSTRING,
1197                                         0, (LPARAM) (sessions[i]));
1198                 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL,
1199                                     (WPARAM) -1, 0);
1200             }
1201           case IDC_PINGEDIT:
1202             if (HIWORD(wParam) == EN_CHANGE)
1203                 MyGetDlgItemInt (hwnd, IDC_PINGEDIT, &cfg.ping_interval);
1204             break;
1205           case IDC_DEL008:
1206           case IDC_DEL127:
1207             if (HIWORD(wParam) == BN_CLICKED ||
1208                 HIWORD(wParam) == BN_DOUBLECLICKED)
1209                 cfg.bksp_is_delete = IsDlgButtonChecked (hwnd, IDC_DEL127);
1210             break;
1211           case IDC_HOMETILDE:
1212           case IDC_HOMERXVT:
1213             if (HIWORD(wParam) == BN_CLICKED ||
1214                 HIWORD(wParam) == BN_DOUBLECLICKED)
1215                 cfg.rxvt_homeend = IsDlgButtonChecked (hwnd, IDC_HOMERXVT);
1216             break;
1217           case IDC_FUNCXTERM:
1218             if (HIWORD(wParam) == BN_CLICKED ||
1219                 HIWORD(wParam) == BN_DOUBLECLICKED)
1220                 cfg.funky_type = 2;
1221             break;
1222           case IDC_FUNCVT400:
1223             if (HIWORD(wParam) == BN_CLICKED ||
1224                 HIWORD(wParam) == BN_DOUBLECLICKED)
1225                 cfg.funky_type = 3;
1226             break;
1227           case IDC_FUNCTILDE:
1228           case IDC_FUNCLINUX:
1229             if (HIWORD(wParam) == BN_CLICKED ||
1230                 HIWORD(wParam) == BN_DOUBLECLICKED)
1231                 cfg.funky_type = IsDlgButtonChecked (hwnd, IDC_FUNCLINUX);
1232             break;
1233           case IDC_KPNORMAL:
1234           case IDC_KPAPPLIC:
1235             if (HIWORD(wParam) == BN_CLICKED ||
1236                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1237                 cfg.app_keypad = IsDlgButtonChecked (hwnd, IDC_KPAPPLIC);
1238                 cfg.nethack_keypad = FALSE;
1239             }
1240             break;
1241           case IDC_KPNH:
1242             if (HIWORD(wParam) == BN_CLICKED ||
1243                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1244                 cfg.app_keypad = FALSE;
1245                 cfg.nethack_keypad = TRUE;
1246             }
1247             break;
1248           case IDC_CURNORMAL:
1249           case IDC_CURAPPLIC:
1250             if (HIWORD(wParam) == BN_CLICKED ||
1251                 HIWORD(wParam) == BN_DOUBLECLICKED)
1252                 cfg.app_cursor = IsDlgButtonChecked (hwnd, IDC_CURAPPLIC);
1253             break;
1254           case IDC_NOAPPLICC:
1255             if (HIWORD(wParam) == BN_CLICKED ||
1256                 HIWORD(wParam) == BN_DOUBLECLICKED)
1257                 cfg.no_applic_c = IsDlgButtonChecked (hwnd, IDC_NOAPPLICC);
1258             break;
1259           case IDC_NOAPPLICK:
1260             if (HIWORD(wParam) == BN_CLICKED ||
1261                 HIWORD(wParam) == BN_DOUBLECLICKED)
1262                 cfg.no_applic_k = IsDlgButtonChecked (hwnd, IDC_NOAPPLICK);
1263             break;
1264           case IDC_ALTF4:
1265             if (HIWORD(wParam) == BN_CLICKED ||
1266                 HIWORD(wParam) == BN_DOUBLECLICKED)
1267                 cfg.alt_f4 = IsDlgButtonChecked (hwnd, IDC_ALTF4);
1268             break;
1269           case IDC_ALTSPACE:
1270             if (HIWORD(wParam) == BN_CLICKED ||
1271                 HIWORD(wParam) == BN_DOUBLECLICKED)
1272                 cfg.alt_space = IsDlgButtonChecked (hwnd, IDC_ALTSPACE);
1273             break;
1274           case IDC_ALTONLY:
1275             if (HIWORD(wParam) == BN_CLICKED ||
1276                 HIWORD(wParam) == BN_DOUBLECLICKED)
1277                 cfg.alt_only = IsDlgButtonChecked (hwnd, IDC_ALTONLY);
1278             break;
1279           case IDC_LDISCTERM:
1280             if (HIWORD(wParam) == BN_CLICKED ||
1281                 HIWORD(wParam) == BN_DOUBLECLICKED)
1282                 cfg.ldisc_term = IsDlgButtonChecked (hwnd, IDC_LDISCTERM);
1283             break;
1284           case IDC_ALWAYSONTOP:
1285             if (HIWORD(wParam) == BN_CLICKED ||
1286                 HIWORD(wParam) == BN_DOUBLECLICKED)
1287                 cfg.alwaysontop = IsDlgButtonChecked (hwnd, IDC_ALWAYSONTOP);
1288             break;
1289           case IDC_SCROLLKEY:
1290             if (HIWORD(wParam) == BN_CLICKED ||
1291                 HIWORD(wParam) == BN_DOUBLECLICKED)
1292                 cfg.scroll_on_key = IsDlgButtonChecked (hwnd, IDC_SCROLLKEY);
1293             break;
1294           case IDC_SCROLLDISP:
1295             if (HIWORD(wParam) == BN_CLICKED ||
1296                 HIWORD(wParam) == BN_DOUBLECLICKED)
1297                 cfg.scroll_on_disp = IsDlgButtonChecked (hwnd, IDC_SCROLLDISP);
1298             break;
1299           case IDC_COMPOSEKEY:
1300             if (HIWORD(wParam) == BN_CLICKED ||
1301                 HIWORD(wParam) == BN_DOUBLECLICKED)
1302                 cfg.compose_key = IsDlgButtonChecked (hwnd, IDC_COMPOSEKEY);
1303             break;
1304           case IDC_WRAPMODE:
1305             if (HIWORD(wParam) == BN_CLICKED ||
1306                 HIWORD(wParam) == BN_DOUBLECLICKED)
1307                 cfg.wrap_mode = IsDlgButtonChecked (hwnd, IDC_WRAPMODE);
1308             break;
1309           case IDC_DECOM:
1310             if (HIWORD(wParam) == BN_CLICKED ||
1311                 HIWORD(wParam) == BN_DOUBLECLICKED)
1312                 cfg.dec_om = IsDlgButtonChecked (hwnd, IDC_DECOM);
1313             break;
1314           case IDC_LFHASCR:
1315             if (HIWORD(wParam) == BN_CLICKED ||
1316                 HIWORD(wParam) == BN_DOUBLECLICKED)
1317                 cfg.lfhascr = IsDlgButtonChecked (hwnd, IDC_LFHASCR);
1318             break;
1319           case IDC_ROWSEDIT:
1320             if (HIWORD(wParam) == EN_CHANGE)
1321                 MyGetDlgItemInt (hwnd, IDC_ROWSEDIT, &cfg.height);
1322             break;
1323           case IDC_COLSEDIT:
1324             if (HIWORD(wParam) == EN_CHANGE)
1325                 MyGetDlgItemInt (hwnd, IDC_COLSEDIT, &cfg.width);
1326             break;
1327           case IDC_SAVEEDIT:
1328             if (HIWORD(wParam) == EN_CHANGE)
1329                 MyGetDlgItemInt (hwnd, IDC_SAVEEDIT, &cfg.savelines);
1330             break;
1331           case IDC_CHOOSEFONT:
1332             lf.lfHeight = cfg.fontheight;
1333             lf.lfWidth = lf.lfEscapement = lf.lfOrientation = 0;
1334             lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = 0;
1335             lf.lfWeight = (cfg.fontisbold ? FW_BOLD : 0);
1336             lf.lfCharSet = cfg.fontcharset;
1337             lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
1338             lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1339             lf.lfQuality = DEFAULT_QUALITY;
1340             lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
1341             strncpy (lf.lfFaceName, cfg.font, sizeof(lf.lfFaceName)-1);
1342             lf.lfFaceName[sizeof(lf.lfFaceName)-1] = '\0';
1343
1344             cf.lStructSize = sizeof(cf);
1345             cf.hwndOwner = hwnd;
1346             cf.lpLogFont = &lf;
1347             cf.Flags = CF_FIXEDPITCHONLY | CF_FORCEFONTEXIST |
1348                 CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
1349
1350             if (ChooseFont (&cf)) {
1351                 strncpy (cfg.font, lf.lfFaceName, sizeof(cfg.font)-1);
1352                 cfg.font[sizeof(cfg.font)-1] = '\0';
1353                 cfg.fontisbold = (lf.lfWeight == FW_BOLD);
1354                 cfg.fontcharset = lf.lfCharSet;
1355                 cfg.fontheight = lf.lfHeight;
1356                 fmtfont (fontstatic);
1357                 SetDlgItemText (hwnd, IDC_FONTSTATIC, fontstatic);
1358             }
1359             break;
1360           case IDC_BEEP:
1361             if (HIWORD(wParam) == BN_CLICKED ||
1362                 HIWORD(wParam) == BN_DOUBLECLICKED)
1363                 cfg.beep = IsDlgButtonChecked (hwnd, IDC_BEEP);
1364             break;
1365           case IDC_BLINKTEXT:
1366             if (HIWORD(wParam) == BN_CLICKED ||
1367                 HIWORD(wParam) == BN_DOUBLECLICKED)
1368                 cfg.blinktext = IsDlgButtonChecked (hwnd, IDC_BLINKTEXT);
1369             break;
1370           case IDC_BCE:
1371             if (HIWORD(wParam) == BN_CLICKED ||
1372                 HIWORD(wParam) == BN_DOUBLECLICKED)
1373                 cfg.bce = IsDlgButtonChecked (hwnd, IDC_BCE);
1374             break;
1375           case IDC_WINNAME:
1376             if (HIWORD(wParam) == BN_CLICKED ||
1377                 HIWORD(wParam) == BN_DOUBLECLICKED)
1378                 cfg.win_name_always = IsDlgButtonChecked (hwnd, IDC_WINNAME);
1379             break;
1380           case IDC_BLINKCUR:
1381             if (HIWORD(wParam) == BN_CLICKED ||
1382                 HIWORD(wParam) == BN_DOUBLECLICKED)
1383                 cfg.blink_cur = IsDlgButtonChecked (hwnd, IDC_BLINKCUR);
1384             break;
1385           case IDC_SCROLLBAR:
1386             if (HIWORD(wParam) == BN_CLICKED ||
1387                 HIWORD(wParam) == BN_DOUBLECLICKED)
1388                 cfg.scrollbar = IsDlgButtonChecked (hwnd, IDC_SCROLLBAR);
1389             break;
1390           case IDC_LOCKSIZE:
1391              if (HIWORD(wParam) == BN_CLICKED ||
1392                  HIWORD(wParam) == BN_DOUBLECLICKED)
1393                 cfg.locksize = IsDlgButtonChecked (hwnd, IDC_LOCKSIZE);
1394             break;
1395           case IDC_WINEDIT:
1396             if (HIWORD(wParam) == EN_CHANGE)
1397                 GetDlgItemText (hwnd, IDC_WINEDIT, cfg.wintitle,
1398                                 sizeof(cfg.wintitle)-1);
1399             break;
1400           case IDC_CLOSEEXIT:
1401             if (HIWORD(wParam) == BN_CLICKED ||
1402                 HIWORD(wParam) == BN_DOUBLECLICKED)
1403                 cfg.close_on_exit = IsDlgButtonChecked (hwnd, IDC_CLOSEEXIT);
1404             break;
1405           case IDC_CLOSEWARN:
1406             if (HIWORD(wParam) == BN_CLICKED ||
1407                 HIWORD(wParam) == BN_DOUBLECLICKED)
1408                 cfg.warn_on_close = IsDlgButtonChecked (hwnd, IDC_CLOSEWARN);
1409             break;
1410           case IDC_TTEDIT:
1411             if (HIWORD(wParam) == EN_CHANGE)
1412             GetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype,
1413                             sizeof(cfg.termtype)-1);
1414             break;
1415           case IDC_TSEDIT:
1416             if (HIWORD(wParam) == EN_CHANGE)
1417                 GetDlgItemText (hwnd, IDC_TSEDIT, cfg.termspeed,
1418                                 sizeof(cfg.termspeed)-1);
1419             break;
1420           case IDC_LOGEDIT:
1421             if (HIWORD(wParam) == EN_CHANGE)
1422                 GetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username,
1423                                 sizeof(cfg.username)-1);
1424             break;
1425           case IDC_EMBSD:
1426           case IDC_EMRFC:
1427             cfg.rfc_environ = IsDlgButtonChecked (hwnd, IDC_EMRFC);
1428             break;
1429           case IDC_ENVADD:
1430             if (HIWORD(wParam) == BN_CLICKED ||
1431                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1432               char str[sizeof(cfg.environmt)];
1433                 char *p;
1434                 GetDlgItemText (hwnd, IDC_VAREDIT, str, sizeof(str)-1);
1435                 if (!*str) {
1436                     MessageBeep(0);
1437                     break;
1438                 }
1439                 p = str + strlen(str);
1440                 *p++ = '\t';
1441                 GetDlgItemText (hwnd, IDC_VALEDIT, p, sizeof(str)-1-(p-str));
1442                 if (!*p) {
1443                     MessageBeep(0);
1444                     break;
1445                 }
1446               p = cfg.environmt;
1447                 while (*p) {
1448                     while (*p) p++;
1449                     p++;
1450                 }
1451               if ((p-cfg.environmt) + strlen(str) + 2 < sizeof(cfg.environmt)) {
1452                     strcpy (p, str);
1453                     p[strlen(str)+1] = '\0';
1454                     SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_ADDSTRING,
1455                                         0, (LPARAM)str);
1456                     SetDlgItemText (hwnd, IDC_VAREDIT, "");
1457                     SetDlgItemText (hwnd, IDC_VALEDIT, "");
1458                 } else {
1459                     MessageBox(hwnd, "Environment too big", "PuTTY Error",
1460                                MB_OK | MB_ICONERROR);
1461                 }
1462             }
1463             break;
1464           case IDC_ENVREMOVE:
1465             if (HIWORD(wParam) != BN_CLICKED &&
1466                 HIWORD(wParam) != BN_DOUBLECLICKED)
1467                 break;
1468             i = SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_GETCURSEL, 0, 0);
1469             if (i == LB_ERR)
1470                 MessageBeep (0);
1471             else {
1472                 char *p, *q;
1473
1474                 SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_DELETESTRING,
1475                                     i, 0);
1476               p = cfg.environmt;
1477                 while (i > 0) {
1478                     if (!*p)
1479                         goto disaster;
1480                     while (*p) p++;
1481                     p++;
1482                     i--;
1483                 }
1484                 q = p;
1485                 if (!*p)
1486                     goto disaster;
1487                 while (*p) p++;
1488                 p++;
1489                 while (*p) {
1490                     while (*p)
1491                         *q++ = *p++;
1492                     *q++ = *p++;
1493                 }
1494                 *q = '\0';
1495                 disaster:;
1496             }
1497             break;
1498           case IDC_NOPTY:
1499             if (HIWORD(wParam) == BN_CLICKED ||
1500                 HIWORD(wParam) == BN_DOUBLECLICKED)
1501                 cfg.nopty = IsDlgButtonChecked (hwnd, IDC_NOPTY);
1502             break;
1503           case IDC_COMPRESS:
1504             if (HIWORD(wParam) == BN_CLICKED ||
1505                 HIWORD(wParam) == BN_DOUBLECLICKED)
1506                 cfg.compression = IsDlgButtonChecked (hwnd, IDC_COMPRESS);
1507             break;
1508           case IDC_BUGGYMAC:
1509             if (HIWORD(wParam) == BN_CLICKED ||
1510                 HIWORD(wParam) == BN_DOUBLECLICKED)
1511                 cfg.buggymac = IsDlgButtonChecked (hwnd, IDC_BUGGYMAC);
1512             break;
1513           case IDC_AGENTFWD:
1514             if (HIWORD(wParam) == BN_CLICKED ||
1515                 HIWORD(wParam) == BN_DOUBLECLICKED)
1516                 cfg.agentfwd = IsDlgButtonChecked (hwnd, IDC_AGENTFWD);
1517             break;
1518           case IDC_CIPHER3DES:
1519           case IDC_CIPHERBLOWF:
1520           case IDC_CIPHERDES:
1521             if (HIWORD(wParam) == BN_CLICKED ||
1522                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1523                 if (IsDlgButtonChecked (hwnd, IDC_CIPHER3DES))
1524                     cfg.cipher = CIPHER_3DES;
1525                 else if (IsDlgButtonChecked (hwnd, IDC_CIPHERBLOWF))
1526                     cfg.cipher = CIPHER_BLOWFISH;
1527                 else if (IsDlgButtonChecked (hwnd, IDC_CIPHERDES))
1528                     cfg.cipher = CIPHER_DES;
1529             }
1530             break;
1531           case IDC_SSHPROT1:
1532           case IDC_SSHPROT2:
1533             if (HIWORD(wParam) == BN_CLICKED ||
1534                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1535                 if (IsDlgButtonChecked (hwnd, IDC_SSHPROT1))
1536                     cfg.sshprot = 1;
1537                 else if (IsDlgButtonChecked (hwnd, IDC_SSHPROT2))
1538                     cfg.sshprot = 2;
1539             }
1540             break;
1541           case IDC_AUTHTIS:
1542             if (HIWORD(wParam) == BN_CLICKED ||
1543                 HIWORD(wParam) == BN_DOUBLECLICKED)
1544                 cfg.try_tis_auth = IsDlgButtonChecked (hwnd, IDC_AUTHTIS);
1545             break;
1546           case IDC_PKEDIT:
1547             if (HIWORD(wParam) == EN_CHANGE)
1548                 GetDlgItemText (hwnd, IDC_PKEDIT, cfg.keyfile,
1549                                 sizeof(cfg.keyfile)-1);
1550             break;
1551           case IDC_CMDEDIT:
1552             if (HIWORD(wParam) == EN_CHANGE)
1553                 GetDlgItemText (hwnd, IDC_CMDEDIT, cfg.remote_cmd,
1554                                 sizeof(cfg.remote_cmd)-1);
1555             break;
1556           case IDC_PKBUTTON:
1557             memset(&of, 0, sizeof(of));
1558 #ifdef OPENFILENAME_SIZE_VERSION_400
1559             of.lStructSize = OPENFILENAME_SIZE_VERSION_400;
1560 #else
1561             of.lStructSize = sizeof(of);
1562 #endif
1563             of.hwndOwner = hwnd;
1564             of.lpstrFilter = "All Files\0*\0\0\0";
1565             of.lpstrCustomFilter = NULL;
1566             of.nFilterIndex = 1;
1567             of.lpstrFile = filename; strcpy(filename, cfg.keyfile);
1568             of.nMaxFile = sizeof(filename);
1569             of.lpstrFileTitle = NULL;
1570             of.lpstrInitialDir = NULL;
1571             of.lpstrTitle = "Select Public Key File";
1572             of.Flags = 0;
1573             if (GetOpenFileName(&of)) {
1574                 strcpy(cfg.keyfile, filename);
1575                 SetDlgItemText (hwnd, IDC_PKEDIT, cfg.keyfile);
1576             }
1577             break;
1578           case IDC_MBWINDOWS:
1579           case IDC_MBXTERM:
1580             cfg.mouse_is_xterm = IsDlgButtonChecked (hwnd, IDC_MBXTERM);
1581             break;
1582           case IDC_CCSET:
1583             {
1584                 BOOL ok;
1585                 int i;
1586                 int n = GetDlgItemInt (hwnd, IDC_CCEDIT, &ok, FALSE);
1587
1588                 if (!ok)
1589                     MessageBeep (0);
1590                 else {
1591                     for (i=0; i<256; i++)
1592                         if (SendDlgItemMessage (hwnd, IDC_CCLIST, LB_GETSEL,
1593                                                 i, 0)) {
1594                             char str[100];
1595                             cfg.wordness[i] = n;
1596                             SendDlgItemMessage (hwnd, IDC_CCLIST,
1597                                                 LB_DELETESTRING, i, 0);
1598                             sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
1599                                     (i>=0x21 && i != 0x7F) ? i : ' ',
1600                                     cfg.wordness[i]);
1601                             SendDlgItemMessage (hwnd, IDC_CCLIST,
1602                                                 LB_INSERTSTRING, i,
1603                                                 (LPARAM)str);
1604                         }
1605                 }
1606             }
1607             break;
1608           case IDC_BOLDCOLOUR:
1609             if (HIWORD(wParam) == BN_CLICKED ||
1610                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1611                 int n, i;
1612                 cfg.bold_colour = IsDlgButtonChecked (hwnd, IDC_BOLDCOLOUR);
1613                 n = SendDlgItemMessage (hwnd, IDC_COLOURLIST, LB_GETCOUNT, 0, 0);
1614                 if (cfg.bold_colour && n!=22) {
1615                     for (i=0; i<22; i++)
1616                         if (!permcolour[i])
1617                             SendDlgItemMessage (hwnd, IDC_COLOURLIST,
1618                                                 LB_INSERTSTRING, i,
1619                                                 (LPARAM) colours[i]);
1620                 } else if (!cfg.bold_colour && n!=12) {
1621                     for (i=22; i-- ;)
1622                         if (!permcolour[i])
1623                             SendDlgItemMessage (hwnd, IDC_COLOURLIST,
1624                                                 LB_DELETESTRING, i, 0);
1625                 }
1626             }
1627             break;
1628           case IDC_PALETTE:
1629             if (HIWORD(wParam) == BN_CLICKED ||
1630                 HIWORD(wParam) == BN_DOUBLECLICKED)
1631                 cfg.try_palette = IsDlgButtonChecked (hwnd, IDC_PALETTE);
1632             break;
1633           case IDC_COLOURLIST:
1634             if (HIWORD(wParam) == LBN_DBLCLK ||
1635                 HIWORD(wParam) == LBN_SELCHANGE) {
1636                 int i = SendDlgItemMessage (hwnd, IDC_COLOURLIST, LB_GETCURSEL,
1637                                             0, 0);
1638                 if (!cfg.bold_colour)
1639                     i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
1640                 SetDlgItemInt (hwnd, IDC_RVALUE, cfg.colours[i][0], FALSE);
1641                 SetDlgItemInt (hwnd, IDC_GVALUE, cfg.colours[i][1], FALSE);
1642                 SetDlgItemInt (hwnd, IDC_BVALUE, cfg.colours[i][2], FALSE);
1643             }
1644             break;
1645           case IDC_CHANGE:
1646             if (HIWORD(wParam) == BN_CLICKED ||
1647                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1648                 static CHOOSECOLOR cc;
1649                 static DWORD custom[16] = {0};   /* zero initialisers */
1650                 int i = SendDlgItemMessage (hwnd, IDC_COLOURLIST, LB_GETCURSEL,
1651                                             0, 0);
1652                 if (!cfg.bold_colour)
1653                     i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
1654                 cc.lStructSize = sizeof(cc);
1655                 cc.hwndOwner = hwnd;
1656                 cc.hInstance = (HWND)hinst;
1657                 cc.lpCustColors = custom;
1658                 cc.rgbResult = RGB (cfg.colours[i][0], cfg.colours[i][1],
1659                                     cfg.colours[i][2]);
1660                 cc.Flags = CC_FULLOPEN | CC_RGBINIT;
1661                 if (ChooseColor(&cc)) {
1662                     cfg.colours[i][0] =
1663                         (unsigned char) (cc.rgbResult & 0xFF);
1664                     cfg.colours[i][1] =
1665                         (unsigned char) (cc.rgbResult >> 8) & 0xFF;
1666                     cfg.colours[i][2] =
1667                         (unsigned char) (cc.rgbResult >> 16) & 0xFF;
1668                     SetDlgItemInt (hwnd, IDC_RVALUE, cfg.colours[i][0],
1669                                    FALSE);
1670                     SetDlgItemInt (hwnd, IDC_GVALUE, cfg.colours[i][1],
1671                                    FALSE);
1672                     SetDlgItemInt (hwnd, IDC_BVALUE, cfg.colours[i][2],
1673                                    FALSE);
1674                 }
1675             }
1676             break;
1677           case IDC_NOXLAT:
1678           case IDC_KOI8WIN1251:
1679           case IDC_88592WIN1250:
1680           case IDC_88592CP852:
1681             cfg.xlat_enablekoiwin =
1682                 IsDlgButtonChecked (hwnd, IDC_KOI8WIN1251);
1683             cfg.xlat_88592w1250 =
1684                 IsDlgButtonChecked (hwnd, IDC_88592WIN1250);
1685             cfg.xlat_88592cp852 =
1686                 IsDlgButtonChecked (hwnd, IDC_88592CP852);
1687             break;
1688           case IDC_CAPSLOCKCYR:
1689             if (HIWORD(wParam) == BN_CLICKED ||
1690                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1691                 cfg.xlat_capslockcyr =
1692                     IsDlgButtonChecked (hwnd, IDC_CAPSLOCKCYR);
1693             }
1694             break;
1695           case IDC_VTXWINDOWS:
1696           case IDC_VTOEMANSI:
1697           case IDC_VTOEMONLY:
1698           case IDC_VTPOORMAN:
1699             cfg.vtmode =
1700                 (IsDlgButtonChecked (hwnd, IDC_VTXWINDOWS) ? VT_XWINDOWS :
1701                  IsDlgButtonChecked (hwnd, IDC_VTOEMANSI) ? VT_OEMANSI :
1702                  IsDlgButtonChecked (hwnd, IDC_VTOEMONLY) ? VT_OEMONLY :
1703                  VT_POORMAN);
1704             break;
1705         }
1706         return 0;
1707       case WM_CLOSE:
1708         EndDialog (hwnd, 0);
1709         return 0;
1710
1711         /* Grrr Explorer will maximize Dialogs! */
1712       case WM_SIZE:
1713         if (wParam == SIZE_MAXIMIZED)
1714            force_normal(hwnd);
1715         return 0;
1716     }
1717     return 0;
1718 }
1719
1720 static int CALLBACK MainDlgProc (HWND hwnd, UINT msg,
1721                                  WPARAM wParam, LPARAM lParam) {
1722     static HWND page = NULL;
1723
1724     if (msg == WM_COMMAND && LOWORD(wParam) == IDOK) {
1725     }
1726     if (msg == WM_COMMAND && LOWORD(wParam) == IDCX_ABOUT) {
1727         EnableWindow(hwnd, 0);
1728         DialogBox(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
1729                   GetParent(hwnd), AboutProc);
1730         EnableWindow(hwnd, 1);
1731         SetActiveWindow(hwnd);
1732     }
1733     return GenericMainDlgProc (hwnd, msg, wParam, lParam, 0);
1734 }
1735
1736 static int CALLBACK ReconfDlgProc (HWND hwnd, UINT msg,
1737                                    WPARAM wParam, LPARAM lParam) {
1738     static HWND page;
1739     return GenericMainDlgProc (hwnd, msg, wParam, lParam, 1);
1740 }
1741
1742 void defuse_showwindow(void) {
1743     /*
1744      * Work around the fact that the app's first call to ShowWindow
1745      * will ignore the default in favour of the shell-provided
1746      * setting.
1747      */
1748     {
1749         HWND hwnd;
1750         hwnd = CreateDialog (hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
1751                              NULL, NullDlgProc);
1752         ShowWindow(hwnd, SW_HIDE);
1753         DestroyWindow(hwnd);
1754     }
1755 }
1756
1757 int do_config (void) {
1758     int ret;
1759
1760     get_sesslist(TRUE);
1761     savedsession[0] = '\0';
1762     ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_MAINBOX), NULL, MainDlgProc);
1763     get_sesslist(FALSE);
1764
1765     return ret;
1766 }
1767
1768 int do_reconfig (HWND hwnd) {
1769     Config backup_cfg;
1770     int ret;
1771
1772     backup_cfg = cfg;                  /* structure copy */
1773     ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_RECONF), hwnd, ReconfDlgProc);
1774     if (!ret)
1775         cfg = backup_cfg;              /* structure copy */
1776     else
1777         force_normal(hwnd);
1778
1779     return ret;
1780 }
1781
1782 void logevent (char *string) {
1783     if (nevents >= negsize) {
1784         negsize += 64;
1785         events = srealloc (events, negsize * sizeof(*events));
1786     }
1787     events[nevents] = smalloc(1+strlen(string));
1788     strcpy (events[nevents], string);
1789     nevents++;
1790     if (logbox) {
1791         int count;
1792         SendDlgItemMessage (logbox, IDN_LIST, LB_ADDSTRING,
1793                             0, (LPARAM)string);
1794         count = SendDlgItemMessage (logbox, IDN_LIST, LB_GETCOUNT, 0, 0);
1795         SendDlgItemMessage (logbox, IDN_LIST, LB_SETTOPINDEX, count-1, 0);
1796     }
1797 }
1798
1799 void showeventlog (HWND hwnd) {
1800     if (!logbox) {
1801         logbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_LOGBOX),
1802                                hwnd, LogProc);
1803         ShowWindow (logbox, SW_SHOWNORMAL);
1804     }
1805 }
1806
1807 void showabout (HWND hwnd) {
1808     if (!abtbox) {
1809         abtbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
1810                                hwnd, AboutProc);
1811         ShowWindow (abtbox, SW_SHOWNORMAL);
1812     }
1813 }
1814
1815 void verify_ssh_host_key(char *host, int port, char *keytype,
1816                          char *keystr, char *fingerprint) {
1817     int ret;
1818
1819     static const char absentmsg[] =
1820         "The server's host key is not cached in the registry. You\n"
1821         "have no guarantee that the server is the computer you\n"
1822         "think it is.\n"
1823         "The server's key fingerprint is:\n"
1824         "%s\n"
1825         "If you trust this host, hit Yes to add the key to\n"
1826         "PuTTY's cache and carry on connecting.\n"
1827         "If you do not trust this host, hit No to abandon the\n"
1828         "connection.\n";
1829
1830     static const char wrongmsg[] =
1831         "WARNING - POTENTIAL SECURITY BREACH!\n"
1832         "\n"
1833         "The server's host key does not match the one PuTTY has\n"
1834         "cached in the registry. This means that either the\n"
1835         "server administrator has changed the host key, or you\n"
1836         "have actually connected to another computer pretending\n"
1837         "to be the server.\n"
1838         "The new key fingerprint is:\n"
1839         "%s\n"
1840         "If you were expecting this change and trust the new key,\n"
1841         "hit Yes to update PuTTY's cache and continue connecting.\n"
1842         "If you want to carry on connecting but without updating\n"
1843         "the cache, hit No.\n"
1844         "If you want to abandon the connection completely, hit\n"
1845         "Cancel. Hitting Cancel is the ONLY guaranteed safe\n"
1846         "choice.\n";
1847
1848     static const char mbtitle[] = "PuTTY Security Alert";
1849
1850     
1851     char message[160+                  /* sensible fingerprint max size */
1852                  (sizeof(absentmsg) > sizeof(wrongmsg) ?
1853                   sizeof(absentmsg) : sizeof(wrongmsg))];
1854
1855     /*
1856      * Verify the key against the registry.
1857      */
1858     ret = verify_host_key(host, port, keytype, keystr);
1859
1860     if (ret == 0)                      /* success - key matched OK */
1861         return;
1862     if (ret == 2) {                    /* key was different */
1863         int mbret;
1864         sprintf(message, wrongmsg, fingerprint);
1865         mbret = MessageBox(NULL, message, mbtitle,
1866                            MB_ICONWARNING | MB_YESNOCANCEL);
1867         if (mbret == IDYES)
1868             store_host_key(host, port, keytype, keystr);
1869         if (mbret == IDCANCEL)
1870             exit(0);
1871     }
1872     if (ret == 1) {                    /* key was absent */
1873         int mbret;
1874         sprintf(message, absentmsg, fingerprint);
1875         mbret = MessageBox(NULL, message, mbtitle,
1876                            MB_ICONWARNING | MB_YESNO);
1877         if (mbret == IDNO)
1878             exit(0);
1879         store_host_key(host, port, keytype, keystr);
1880     }
1881 }