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