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