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