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