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