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