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