]> asedeno.scripts.mit.edu Git - PuTTY_svn.git/blob - windlg.c
Fix a very old bug nobody ever noticed: multiple About boxes :-)
[PuTTY_svn.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 "win_res.h"
17 #include "storage.h"
18
19 #define NPANELS 8
20 #define MAIN_NPANELS 8
21 #define RECONF_NPANELS 5
22
23 static char **events = NULL;
24 static int nevents = 0, negsize = 0;
25
26 static HWND logbox = NULL, abtbox = NULL;
27
28 static void gpps(void *handle, char *name, char *def, char *val, int len) {
29     if (!read_setting_s(handle, name, val, len)) {
30         strncpy(val, def, len);
31         val[len-1] = '\0';
32     }
33 }
34
35 static void gppi(void *handle, char *name, int def, int *i) {
36     *i = read_setting_i(handle, name, def);
37 }
38
39 static HINSTANCE hinst;
40
41 static int readytogo;
42
43 static void save_settings (char *section, int do_host) {
44     int i;
45     char *p;
46     void *sesskey;
47
48     sesskey = open_settings_w(section);
49     if (!sesskey)
50         return;
51
52     write_setting_i (sesskey, "Present", 1);
53     if (do_host) {
54         write_setting_s (sesskey, "HostName", cfg.host);
55         write_setting_i (sesskey, "PortNumber", cfg.port);
56         p = "raw";
57         for (i = 0; backends[i].name != NULL; i++)
58             if (backends[i].protocol == cfg.protocol) {
59                 p = backends[i].name;
60                 break;
61             }
62         write_setting_s (sesskey, "Protocol", p);
63     }
64     write_setting_i (sesskey, "CloseOnExit", !!cfg.close_on_exit);
65     write_setting_i (sesskey, "WarnOnClose", !!cfg.warn_on_close);
66     write_setting_s (sesskey, "TerminalType", cfg.termtype);
67     write_setting_s (sesskey, "TerminalSpeed", cfg.termspeed);
68     {
69       char buf[2*sizeof(cfg.environmt)], *p, *q;
70         p = buf;
71       q = cfg.environmt;
72         while (*q) {
73             while (*q) {
74                 int c = *q++;
75                 if (c == '=' || c == ',' || c == '\\')
76                     *p++ = '\\';
77                 if (c == '\t')
78                     c = '=';
79                 *p++ = c;
80             }
81             *p++ = ',';
82             q++;
83         }
84         *p = '\0';
85         write_setting_s (sesskey, "Environment", buf);
86     }
87     write_setting_s (sesskey, "UserName", cfg.username);
88     write_setting_i (sesskey, "NoPTY", cfg.nopty);
89     write_setting_i (sesskey, "AgentFwd", cfg.agentfwd);
90     write_setting_s (sesskey, "RemoteCmd", cfg.remote_cmd);
91     write_setting_s (sesskey, "Cipher", cfg.cipher == CIPHER_BLOWFISH ? "blowfish" :
92                              cfg.cipher == CIPHER_DES ? "des" : "3des");
93     write_setting_i (sesskey, "AuthTIS", cfg.try_tis_auth);
94     write_setting_i (sesskey, "SshProt", cfg.sshprot);
95     write_setting_s (sesskey, "PublicKeyFile", cfg.keyfile);
96     write_setting_i (sesskey, "RFCEnviron", cfg.rfc_environ);
97     write_setting_i (sesskey, "BackspaceIsDelete", cfg.bksp_is_delete);
98     write_setting_i (sesskey, "RXVTHomeEnd", cfg.rxvt_homeend);
99     write_setting_i (sesskey, "LinuxFunctionKeys", cfg.funky_type);
100     write_setting_i (sesskey, "ApplicationCursorKeys", cfg.app_cursor);
101     write_setting_i (sesskey, "ApplicationKeypad", cfg.app_keypad);
102     write_setting_i (sesskey, "NetHackKeypad", cfg.nethack_keypad);
103     write_setting_i (sesskey, "AltF4", cfg.alt_f4);
104     write_setting_i (sesskey, "AltSpace", cfg.alt_space);
105     write_setting_i (sesskey, "LdiscTerm", cfg.ldisc_term);
106     write_setting_i (sesskey, "BlinkCur", cfg.blink_cur);
107     write_setting_i (sesskey, "Beep", cfg.beep);
108     write_setting_i (sesskey, "ScrollbackLines", cfg.savelines);
109     write_setting_i (sesskey, "DECOriginMode", cfg.dec_om);
110     write_setting_i (sesskey, "AutoWrapMode", cfg.wrap_mode);
111     write_setting_i (sesskey, "LFImpliesCR", cfg.lfhascr);
112     write_setting_i (sesskey, "WinNameAlways", cfg.win_name_always);
113     write_setting_i (sesskey, "TermWidth", cfg.width);
114     write_setting_i (sesskey, "TermHeight", cfg.height);
115     write_setting_s (sesskey, "Font", cfg.font);
116     write_setting_i (sesskey, "FontIsBold", cfg.fontisbold);
117     write_setting_i (sesskey, "FontCharSet", cfg.fontcharset);
118     write_setting_i (sesskey, "FontHeight", cfg.fontheight);
119     write_setting_i (sesskey, "FontVTMode", cfg.vtmode);
120     write_setting_i (sesskey, "TryPalette", cfg.try_palette);
121     write_setting_i (sesskey, "BoldAsColour", cfg.bold_colour);
122     for (i=0; i<22; i++) {
123         char buf[20], buf2[30];
124         sprintf(buf, "Colour%d", i);
125         sprintf(buf2, "%d,%d,%d", cfg.colours[i][0],
126                 cfg.colours[i][1], cfg.colours[i][2]);
127         write_setting_s (sesskey, buf, buf2);
128     }
129     write_setting_i (sesskey, "MouseIsXterm", cfg.mouse_is_xterm);
130     for (i=0; i<256; i+=32) {
131         char buf[20], buf2[256];
132         int j;
133         sprintf(buf, "Wordness%d", i);
134         *buf2 = '\0';
135         for (j=i; j<i+32; j++) {
136             sprintf(buf2+strlen(buf2), "%s%d",
137                     (*buf2 ? "," : ""), cfg.wordness[j]);
138         }
139         write_setting_s (sesskey, buf, buf2);
140     }
141     write_setting_i (sesskey, "KoiWinXlat", cfg.xlat_enablekoiwin);
142     write_setting_i (sesskey, "88592Xlat", cfg.xlat_88592w1250);
143     write_setting_i (sesskey, "CapsLockCyr", cfg.xlat_capslockcyr);
144     write_setting_i (sesskey, "ScrollBar", cfg.scrollbar);
145     write_setting_i (sesskey, "ScrollOnKey", cfg.scroll_on_key);
146     write_setting_i (sesskey, "LockSize", cfg.locksize);
147     write_setting_i (sesskey, "BCE", cfg.bce);
148     write_setting_i (sesskey, "BlinkText", cfg.blinktext);
149
150     close_settings_w(sesskey);
151 }
152
153 static void load_settings (char *section, int do_host) {
154     int i;
155     char prot[10];
156     void *sesskey;
157
158     sesskey = open_settings_r(section);
159
160     gpps (sesskey, "HostName", "", cfg.host, sizeof(cfg.host));
161     gppi (sesskey, "PortNumber", default_port, &cfg.port);
162
163     gpps (sesskey, "Protocol", "default", prot, 10);
164     cfg.protocol = default_protocol;
165     for (i = 0; backends[i].name != NULL; i++)
166         if (!strcmp(prot, backends[i].name)) {
167             cfg.protocol = backends[i].protocol;
168             break;
169         }
170
171     gppi (sesskey, "CloseOnExit", 1, &cfg.close_on_exit);
172     gppi (sesskey, "WarnOnClose", 1, &cfg.warn_on_close);
173     gpps (sesskey, "TerminalType", "xterm", cfg.termtype,
174           sizeof(cfg.termtype));
175     gpps (sesskey, "TerminalSpeed", "38400,38400", cfg.termspeed,
176           sizeof(cfg.termspeed));
177     {
178       char buf[2*sizeof(cfg.environmt)], *p, *q;
179         gpps (sesskey, "Environment", "", buf, sizeof(buf));
180         p = buf;
181         q = cfg.environmt;
182         while (*p) {
183             while (*p && *p != ',') {
184                 int c = *p++;
185                 if (c == '=')
186                     c = '\t';
187                 if (c == '\\')
188                     c = *p++;
189                 *q++ = c;
190             }
191             if (*p == ',') p++;
192             *q++ = '\0';
193         }
194         *q = '\0';
195     }
196     gpps (sesskey, "UserName", "", cfg.username, sizeof(cfg.username));
197     gppi (sesskey, "NoPTY", 0, &cfg.nopty);
198     gppi (sesskey, "AgentFwd", 0, &cfg.agentfwd);
199     gpps (sesskey, "RemoteCmd", "", cfg.remote_cmd, sizeof(cfg.remote_cmd));
200     {
201         char cipher[10];
202         gpps (sesskey, "Cipher", "3des", cipher, 10);
203         if (!strcmp(cipher, "blowfish"))
204             cfg.cipher = CIPHER_BLOWFISH;
205         else if (!strcmp(cipher, "des"))
206             cfg.cipher = CIPHER_DES;
207         else
208             cfg.cipher = CIPHER_3DES;
209     }
210     gppi (sesskey, "SshProt", 1, &cfg.sshprot);
211     gppi (sesskey, "AuthTIS", 0, &cfg.try_tis_auth);
212     gpps (sesskey, "PublicKeyFile", "", cfg.keyfile, sizeof(cfg.keyfile));
213     gppi (sesskey, "RFCEnviron", 0, &cfg.rfc_environ);
214     gppi (sesskey, "BackspaceIsDelete", 1, &cfg.bksp_is_delete);
215     gppi (sesskey, "RXVTHomeEnd", 0, &cfg.rxvt_homeend);
216     gppi (sesskey, "LinuxFunctionKeys", 0, &cfg.funky_type);
217     gppi (sesskey, "ApplicationCursorKeys", 0, &cfg.app_cursor);
218     gppi (sesskey, "ApplicationKeypad", 0, &cfg.app_keypad);
219     gppi (sesskey, "NetHackKeypad", 0, &cfg.nethack_keypad);
220     gppi (sesskey, "AltF4", 1, &cfg.alt_f4);
221     gppi (sesskey, "AltSpace", 0, &cfg.alt_space);
222     gppi (sesskey, "LdiscTerm", 0, &cfg.ldisc_term);
223     gppi (sesskey, "BlinkCur", 0, &cfg.blink_cur);
224     gppi (sesskey, "Beep", 1, &cfg.beep);
225     gppi (sesskey, "ScrollbackLines", 200, &cfg.savelines);
226     gppi (sesskey, "DECOriginMode", 0, &cfg.dec_om);
227     gppi (sesskey, "AutoWrapMode", 1, &cfg.wrap_mode);
228     gppi (sesskey, "LFImpliesCR", 0, &cfg.lfhascr);
229     gppi (sesskey, "WinNameAlways", 0, &cfg.win_name_always);
230     gppi (sesskey, "TermWidth", 80, &cfg.width);
231     gppi (sesskey, "TermHeight", 24, &cfg.height);
232     gpps (sesskey, "Font", "Courier", cfg.font, sizeof(cfg.font));
233     gppi (sesskey, "FontIsBold", 0, &cfg.fontisbold);
234     gppi (sesskey, "FontCharSet", ANSI_CHARSET, &cfg.fontcharset);
235     gppi (sesskey, "FontHeight", 10, &cfg.fontheight);
236     gppi (sesskey, "FontVTMode", VT_OEMANSI, (int *)&cfg.vtmode);
237     gppi (sesskey, "TryPalette", 0, &cfg.try_palette);
238     gppi (sesskey, "BoldAsColour", 1, &cfg.bold_colour);
239     for (i=0; i<22; i++) {
240         static char *defaults[] = {
241             "187,187,187", "255,255,255", "0,0,0", "85,85,85", "0,0,0",
242             "0,255,0", "0,0,0", "85,85,85", "187,0,0", "255,85,85",
243             "0,187,0", "85,255,85", "187,187,0", "255,255,85", "0,0,187",
244             "85,85,255", "187,0,187", "255,85,255", "0,187,187",
245             "85,255,255", "187,187,187", "255,255,255"
246         };
247         char buf[20], buf2[30];
248         int c0, c1, c2;
249         sprintf(buf, "Colour%d", i);
250         gpps (sesskey, buf, defaults[i], buf2, sizeof(buf2));
251         if(sscanf(buf2, "%d,%d,%d", &c0, &c1, &c2) == 3) {
252             cfg.colours[i][0] = c0;
253             cfg.colours[i][1] = c1;
254             cfg.colours[i][2] = c2;
255         }
256     }
257     gppi (sesskey, "MouseIsXterm", 0, &cfg.mouse_is_xterm);
258     for (i=0; i<256; i+=32) {
259         static char *defaults[] = {
260             "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0",
261             "0,1,2,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1",
262             "1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,2",
263             "1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1",
264             "1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1",
265             "1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1",
266             "2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2",
267             "2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2"
268         };
269         char buf[20], buf2[256], *p;
270         int j;
271         sprintf(buf, "Wordness%d", i);
272         gpps (sesskey, buf, defaults[i/32], buf2, sizeof(buf2));
273         p = buf2;
274         for (j=i; j<i+32; j++) {
275             char *q = p;
276             while (*p && *p != ',') p++;
277             if (*p == ',') *p++ = '\0';
278             cfg.wordness[j] = atoi(q);
279         }
280     }
281     gppi (sesskey, "KoiWinXlat", 0, &cfg.xlat_enablekoiwin);
282     gppi (sesskey, "88592Xlat", 0, &cfg.xlat_88592w1250);
283     gppi (sesskey, "CapsLockCyr", 0, &cfg.xlat_capslockcyr);
284     gppi (sesskey, "ScrollBar", 1, &cfg.scrollbar);
285     gppi (sesskey, "ScrollOnKey", 0, &cfg.scroll_on_key);
286     gppi (sesskey, "LockSize", 0, &cfg.locksize);
287     gppi (sesskey, "BCE", 0, &cfg.bce);
288     gppi (sesskey, "BlinkText", 0, &cfg.blinktext);
289
290     close_settings_r(sesskey);
291 }
292
293 static void force_normal(HWND hwnd)
294 {
295 static int recurse = 0;
296
297     WINDOWPLACEMENT wp;
298
299     if(recurse) return;
300     recurse = 1;
301
302     wp.length = sizeof(wp);
303     if (GetWindowPlacement(hwnd, &wp))
304     {
305         wp.showCmd = SW_SHOWNORMAL;
306         SetWindowPlacement(hwnd, &wp);
307     }
308     recurse = 0;
309 }
310
311 static void MyGetDlgItemInt (HWND hwnd, int id, int *result) {
312     BOOL ok;
313     int n;
314     n = GetDlgItemInt (hwnd, id, &ok, FALSE);
315     if (ok)
316         *result = n;
317 }
318
319 static int CALLBACK LogProc (HWND hwnd, UINT msg,
320                              WPARAM wParam, LPARAM lParam) {
321     int i;
322
323     switch (msg) {
324       case WM_INITDIALOG:
325         for (i=0; i<nevents; i++)
326             SendDlgItemMessage (hwnd, IDN_LIST, LB_ADDSTRING,
327                                 0, (LPARAM)events[i]);
328         return 1;
329 /*      case WM_CTLCOLORDLG: */
330 /*      return (int) GetStockObject (LTGRAY_BRUSH); */
331       case WM_COMMAND:
332         switch (LOWORD(wParam)) {
333           case IDOK:
334             logbox = NULL;
335             DestroyWindow (hwnd);
336             return 0;
337           case IDN_COPY:
338             if (HIWORD(wParam) == BN_CLICKED ||
339                 HIWORD(wParam) == BN_DOUBLECLICKED) {
340                 int selcount;
341                 int *selitems;
342                 selcount = SendDlgItemMessage(hwnd, IDN_LIST,
343                                               LB_GETSELCOUNT, 0, 0);
344                 selitems = malloc(selcount * sizeof(int));
345                 if (selitems) {
346                     int count = SendDlgItemMessage(hwnd, IDN_LIST,
347                                                    LB_GETSELITEMS,
348                                                    selcount, (LPARAM)selitems);
349                     int i;
350                     int size;
351                     char *clipdata;
352                     static unsigned char sel_nl[] = SEL_NL;
353
354                     size = 0;
355                     for (i = 0; i < count; i++)
356                         size += strlen(events[selitems[i]]) + sizeof(sel_nl);
357
358                     clipdata = malloc(size);
359                     if (clipdata) {
360                         char *p = clipdata;
361                         for (i = 0; i < count; i++) {
362                             char *q = events[selitems[i]];
363                             int qlen = strlen(q);
364                             memcpy(p, q, qlen);
365                             p += qlen;
366                             memcpy(p, sel_nl, sizeof(sel_nl));
367                             p += sizeof(sel_nl);
368                         }
369                         write_clip(clipdata, size);
370                         term_deselect();
371                         free(clipdata);
372                     }
373                     free(selitems);
374                 }
375             }
376             return 0;
377         }
378         return 0;
379       case WM_CLOSE:
380         logbox = NULL;
381         DestroyWindow (hwnd);
382         return 0;
383     }
384     return 0;
385 }
386
387 static int CALLBACK LicenceProc (HWND hwnd, UINT msg,
388                                  WPARAM wParam, LPARAM lParam) {
389     switch (msg) {
390       case WM_INITDIALOG:
391         return 1;
392       case WM_COMMAND:
393         switch (LOWORD(wParam)) {
394           case IDOK:
395             EndDialog(hwnd, 1);
396             return 0;
397         }
398         return 0;
399       case WM_CLOSE:
400         EndDialog(hwnd, 1);
401         return 0;
402     }
403     return 0;
404 }
405
406 static int CALLBACK AboutProc (HWND hwnd, UINT msg,
407                                WPARAM wParam, LPARAM lParam) {
408     switch (msg) {
409       case WM_INITDIALOG:
410         SetDlgItemText (hwnd, IDA_VERSION, ver);
411         return 1;
412 /*      case WM_CTLCOLORDLG: */
413 /*      return (int) GetStockObject (LTGRAY_BRUSH); */
414 /*      case WM_CTLCOLORSTATIC: */
415 /*      SetBkColor ((HDC)wParam, RGB(192,192,192)); */
416 /*      return (int) GetStockObject (LTGRAY_BRUSH); */
417       case WM_COMMAND:
418         switch (LOWORD(wParam)) {
419           case IDOK:
420             abtbox = NULL;
421             DestroyWindow (hwnd);
422             return 0;
423           case IDA_LICENCE:
424             EnableWindow(hwnd, 0);
425             DialogBox (hinst, MAKEINTRESOURCE(IDD_LICENCEBOX),
426                        NULL, LicenceProc);
427             EnableWindow(hwnd, 1);
428             SetActiveWindow(hwnd);
429             return 0;
430         }
431         return 0;
432       case WM_CLOSE:
433         abtbox = NULL;
434         DestroyWindow (hwnd);
435         return 0;
436     }
437     return 0;
438 }
439
440 static int GeneralPanelProc (HWND hwnd, UINT msg,
441                              WPARAM wParam, LPARAM lParam) {
442     switch (msg) {
443       case WM_INITDIALOG:
444         SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
445         return 1;
446 /*      case WM_CTLCOLORDLG: */
447 /*      return (int) GetStockObject (LTGRAY_BRUSH); */
448 /*      case WM_CTLCOLORSTATIC: */
449 /*      case WM_CTLCOLORBTN: */
450 /*      SetBkColor ((HDC)wParam, RGB(192,192,192)); */
451 /*      return (int) GetStockObject (LTGRAY_BRUSH); */
452       case WM_CLOSE:
453         DestroyWindow (hwnd);
454         return 1;
455     }
456     return 0;
457 }
458
459 static char savedsession[2048];
460
461 static int CALLBACK ConnectionProc (HWND hwnd, UINT msg,
462                                     WPARAM wParam, LPARAM lParam) {
463     int i;
464
465     switch (msg) {
466       case WM_INITDIALOG:
467         SetDlgItemText (hwnd, IDC0_HOST, cfg.host);
468         SetDlgItemText (hwnd, IDC0_SESSEDIT, savedsession);
469         SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE);
470         for (i = 0; i < nsessions; i++)
471             SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING,
472                                 0, (LPARAM) (sessions[i]));
473         CheckRadioButton (hwnd, IDC0_PROTRAW, IDC0_PROTSSH,
474                           cfg.protocol==PROT_SSH ? IDC0_PROTSSH : 
475                           cfg.protocol==PROT_TELNET ? IDC0_PROTTELNET : IDC0_PROTRAW );
476         CheckDlgButton (hwnd, IDC0_CLOSEEXIT, cfg.close_on_exit);
477         CheckDlgButton (hwnd, IDC0_CLOSEWARN, cfg.warn_on_close);
478         break;
479       case WM_LBUTTONUP:
480         /*
481          * Button release should trigger WM_OK if there was a
482          * previous double click on the session list.
483          */
484         ReleaseCapture();
485         if (readytogo)
486             SendMessage (GetParent(hwnd), WM_COMMAND, IDOK, 0);
487         break;
488       case WM_COMMAND:
489         switch (LOWORD(wParam)) {
490           case IDC0_PROTTELNET:
491           case IDC0_PROTSSH:
492           case IDC0_PROTRAW:
493             if (HIWORD(wParam) == BN_CLICKED ||
494                 HIWORD(wParam) == BN_DOUBLECLICKED) {
495                 int i = IsDlgButtonChecked (hwnd, IDC0_PROTSSH);
496                 int j = IsDlgButtonChecked (hwnd, IDC0_PROTTELNET);
497                 cfg.protocol = i ? PROT_SSH : j ? PROT_TELNET : PROT_RAW ;
498                 if ((cfg.protocol == PROT_SSH && cfg.port == 23) ||
499                     (cfg.protocol == PROT_TELNET && cfg.port == 22)) {
500                     cfg.port = i ? 22 : 23;
501                     SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE);
502                 }
503             }
504             break;
505           case IDC0_HOST:
506             if (HIWORD(wParam) == EN_CHANGE)
507                 GetDlgItemText (hwnd, IDC0_HOST, cfg.host,
508                                 sizeof(cfg.host)-1);
509             break;
510           case IDC0_PORT:
511             if (HIWORD(wParam) == EN_CHANGE)
512                 MyGetDlgItemInt (hwnd, IDC0_PORT, &cfg.port);
513             break;
514           case IDC0_CLOSEEXIT:
515             if (HIWORD(wParam) == BN_CLICKED ||
516                 HIWORD(wParam) == BN_DOUBLECLICKED)
517                 cfg.close_on_exit = IsDlgButtonChecked (hwnd, IDC0_CLOSEEXIT);
518             break;
519           case IDC0_CLOSEWARN:
520             if (HIWORD(wParam) == BN_CLICKED ||
521                 HIWORD(wParam) == BN_DOUBLECLICKED)
522                 cfg.warn_on_close = IsDlgButtonChecked (hwnd, IDC0_CLOSEWARN);
523             break;
524           case IDC0_SESSEDIT:
525             if (HIWORD(wParam) == EN_CHANGE) {
526                 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
527                                     (WPARAM) -1, 0);
528                 GetDlgItemText (hwnd, IDC0_SESSEDIT,
529                                 savedsession, sizeof(savedsession)-1);
530                 savedsession[sizeof(savedsession)-1] = '\0';
531             }
532             break;
533           case IDC0_SESSSAVE:
534             if (HIWORD(wParam) == BN_CLICKED ||
535                 HIWORD(wParam) == BN_DOUBLECLICKED) {
536                 /*
537                  * Save a session
538                  */
539                 char str[2048];
540                 GetDlgItemText (hwnd, IDC0_SESSEDIT, str, sizeof(str)-1);
541                 if (!*str) {
542                     int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
543                                                 LB_GETCURSEL, 0, 0);
544                     if (n == LB_ERR) {
545                         MessageBeep(0);
546                         break;
547                     }
548                     strcpy (str, sessions[n]);
549                 }
550                 save_settings (str, !!strcmp(str, "Default Settings"));
551                 get_sesslist (FALSE);
552                 get_sesslist (TRUE);
553                 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_RESETCONTENT,
554                                     0, 0);
555                 for (i = 0; i < nsessions; i++)
556                     SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING,
557                                         0, (LPARAM) (sessions[i]));
558                 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
559                                     (WPARAM) -1, 0);
560             }
561             break;
562           case IDC0_SESSLIST:
563           case IDC0_SESSLOAD:
564             if (LOWORD(wParam) == IDC0_SESSLOAD &&
565                 HIWORD(wParam) != BN_CLICKED &&
566                 HIWORD(wParam) != BN_DOUBLECLICKED)
567                 break;
568             if (LOWORD(wParam) == IDC0_SESSLIST &&
569                 HIWORD(wParam) != LBN_DBLCLK)
570                 break;
571             {
572                 int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
573                                             LB_GETCURSEL, 0, 0);
574                 if (n == LB_ERR) {
575                     MessageBeep(0);
576                     break;
577                 }
578                 load_settings (sessions[n],
579                                !!strcmp(sessions[n], "Default Settings"));
580                 SetDlgItemText (hwnd, IDC0_HOST, cfg.host);
581                 SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE);
582                 CheckRadioButton (hwnd, IDC0_PROTRAW, IDC0_PROTSSH,
583                                   (cfg.protocol==PROT_SSH ? IDC0_PROTSSH :
584                                   cfg.protocol==PROT_TELNET ? IDC0_PROTTELNET : IDC0_PROTRAW));
585                 CheckDlgButton (hwnd, IDC0_CLOSEEXIT, cfg.close_on_exit);
586                 CheckDlgButton (hwnd, IDC0_CLOSEWARN, cfg.warn_on_close);
587                 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
588                                     (WPARAM) -1, 0);
589             }
590             if (LOWORD(wParam) == IDC0_SESSLIST) {
591                 /*
592                  * A double-click on a saved session should
593                  * actually start the session, not just load it.
594                  * Unless it's Default Settings or some other
595                  * host-less set of saved settings.
596                  */
597                 if (*cfg.host) {
598                     readytogo = TRUE;
599                     SetCapture(hwnd);
600                 }
601             }
602             break;
603           case IDC0_SESSDEL:
604             if (HIWORD(wParam) == BN_CLICKED ||
605                 HIWORD(wParam) == BN_DOUBLECLICKED) {
606                 int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
607                                             LB_GETCURSEL, 0, 0);
608                 if (n == LB_ERR || n == 0) {
609                     MessageBeep(0);
610                     break;
611                 }
612                 del_settings(sessions[n]);
613                 get_sesslist (FALSE);
614                 get_sesslist (TRUE);
615                 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_RESETCONTENT,
616                                     0, 0);
617                 for (i = 0; i < nsessions; i++)
618                     SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING,
619                                         0, (LPARAM) (sessions[i]));
620                 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
621                                     (WPARAM) -1, 0);
622             }
623         }
624     }
625     return GeneralPanelProc (hwnd, msg, wParam, lParam);
626 }
627
628 static int CALLBACK KeyboardProc (HWND hwnd, UINT msg,
629                                     WPARAM wParam, LPARAM lParam) {
630     switch (msg) {
631       case WM_INITDIALOG:
632         CheckRadioButton (hwnd, IDC1_DEL008, IDC1_DEL127,
633                           cfg.bksp_is_delete ? IDC1_DEL127 : IDC1_DEL008);
634         CheckRadioButton (hwnd, IDC1_HOMETILDE, IDC1_HOMERXVT,
635                           cfg.rxvt_homeend ? IDC1_HOMERXVT : IDC1_HOMETILDE);
636         CheckRadioButton (hwnd, IDC1_FUNCTILDE, IDC1_FUNCXTERM,
637                           cfg.funky_type ? 
638                           (cfg.funky_type==2 ? IDC1_FUNCXTERM 
639                            : IDC1_FUNCLINUX )
640                           : IDC1_FUNCTILDE);
641         CheckRadioButton (hwnd, IDC1_CURNORMAL, IDC1_CURAPPLIC,
642                           cfg.app_cursor ? IDC1_CURAPPLIC : IDC1_CURNORMAL);
643         CheckRadioButton (hwnd, IDC1_KPNORMAL, IDC1_KPNH,
644                           cfg.nethack_keypad ? IDC1_KPNH :
645                           cfg.app_keypad ? IDC1_KPAPPLIC : IDC1_KPNORMAL);
646         CheckDlgButton (hwnd, IDC1_ALTF4, cfg.alt_f4);
647         CheckDlgButton (hwnd, IDC1_ALTSPACE, cfg.alt_space);
648         CheckDlgButton (hwnd, IDC1_LDISCTERM, cfg.ldisc_term);
649         CheckDlgButton (hwnd, IDC1_SCROLLKEY, cfg.scroll_on_key);
650         break;
651       case WM_COMMAND:
652         if (HIWORD(wParam) == BN_CLICKED ||
653             HIWORD(wParam) == BN_DOUBLECLICKED)
654             switch (LOWORD(wParam)) {
655               case IDC1_DEL008:
656               case IDC1_DEL127:
657                 cfg.bksp_is_delete = IsDlgButtonChecked (hwnd, IDC1_DEL127);
658                 break;
659               case IDC1_HOMETILDE:
660               case IDC1_HOMERXVT:
661                 cfg.rxvt_homeend = IsDlgButtonChecked (hwnd, IDC1_HOMERXVT);
662                 break;
663               case IDC1_FUNCXTERM:
664                 cfg.funky_type = 2;
665                 break;
666               case IDC1_FUNCTILDE:
667               case IDC1_FUNCLINUX:
668                 cfg.funky_type = IsDlgButtonChecked (hwnd, IDC1_FUNCLINUX);
669                 break;
670               case IDC1_KPNORMAL:
671               case IDC1_KPAPPLIC:
672                 cfg.app_keypad = IsDlgButtonChecked (hwnd, IDC1_KPAPPLIC);
673                 cfg.nethack_keypad = FALSE;
674                 break;
675               case IDC1_KPNH:
676                 cfg.app_keypad = FALSE;
677                 cfg.nethack_keypad = TRUE;
678                 break;
679               case IDC1_CURNORMAL:
680               case IDC1_CURAPPLIC:
681                 cfg.app_cursor = IsDlgButtonChecked (hwnd, IDC1_CURAPPLIC);
682                 break;
683               case IDC1_ALTF4:
684                 if (HIWORD(wParam) == BN_CLICKED ||
685                     HIWORD(wParam) == BN_DOUBLECLICKED)
686                     cfg.alt_f4 = IsDlgButtonChecked (hwnd, IDC1_ALTF4);
687                 break;
688               case IDC1_ALTSPACE:
689                 if (HIWORD(wParam) == BN_CLICKED ||
690                     HIWORD(wParam) == BN_DOUBLECLICKED)
691                     cfg.alt_space = IsDlgButtonChecked (hwnd, IDC1_ALTSPACE);
692                 break;
693               case IDC1_LDISCTERM:
694                 if (HIWORD(wParam) == BN_CLICKED ||
695                     HIWORD(wParam) == BN_DOUBLECLICKED)
696                     cfg.ldisc_term = IsDlgButtonChecked (hwnd, IDC1_LDISCTERM);
697                 break;
698               case IDC1_SCROLLKEY:
699                 if (HIWORD(wParam) == BN_CLICKED ||
700                     HIWORD(wParam) == BN_DOUBLECLICKED)
701                     cfg.scroll_on_key = IsDlgButtonChecked (hwnd, IDC1_SCROLLKEY);
702                 break;
703             }
704     }
705     return GeneralPanelProc (hwnd, msg, wParam, lParam);
706 }
707
708 static void fmtfont (char *buf) {
709     sprintf (buf, "Font: %s, ", cfg.font);
710     if (cfg.fontisbold)
711         strcat(buf, "bold, ");
712     if (cfg.fontheight == 0)
713         strcat (buf, "default height");
714     else
715         sprintf (buf+strlen(buf), "%d-%s",
716                  (cfg.fontheight < 0 ? -cfg.fontheight : cfg.fontheight),
717                  (cfg.fontheight < 0 ? "pixel" : "point"));
718 }
719
720 static int CALLBACK TerminalProc (HWND hwnd, UINT msg,
721                                     WPARAM wParam, LPARAM lParam) {
722     CHOOSEFONT cf;
723     LOGFONT lf;
724     char fontstatic[256];
725
726     switch (msg) {
727       case WM_INITDIALOG:
728         CheckDlgButton (hwnd, IDC2_WRAPMODE, cfg.wrap_mode);
729         CheckDlgButton (hwnd, IDC2_WINNAME, cfg.win_name_always);
730         CheckDlgButton (hwnd, IDC2_DECOM, cfg.dec_om);
731         CheckDlgButton (hwnd, IDC2_LFHASCR, cfg.lfhascr);
732         SetDlgItemInt (hwnd, IDC2_ROWSEDIT, cfg.height, FALSE);
733         SetDlgItemInt (hwnd, IDC2_COLSEDIT, cfg.width, FALSE);
734         SetDlgItemInt (hwnd, IDC2_SAVEEDIT, cfg.savelines, FALSE);
735         fmtfont (fontstatic);
736         SetDlgItemText (hwnd, IDC2_FONTSTATIC, fontstatic);
737         CheckDlgButton (hwnd, IDC1_BLINKCUR, cfg.blink_cur);
738         CheckDlgButton (hwnd, IDC1_BEEP, cfg.beep);
739         CheckDlgButton (hwnd, IDC2_SCROLLBAR, cfg.scrollbar);
740         CheckDlgButton (hwnd, IDC2_LOCKSIZE, cfg.locksize);
741         CheckDlgButton (hwnd, IDC2_BCE, cfg.bce);
742         CheckDlgButton (hwnd, IDC2_BLINKTEXT, cfg.blinktext);
743         break;
744       case WM_COMMAND:
745         switch (LOWORD(wParam)) {
746           case IDC2_WRAPMODE:
747             if (HIWORD(wParam) == BN_CLICKED ||
748                 HIWORD(wParam) == BN_DOUBLECLICKED)
749                 cfg.wrap_mode = IsDlgButtonChecked (hwnd, IDC2_WRAPMODE);
750             break;
751           case IDC2_WINNAME:
752             if (HIWORD(wParam) == BN_CLICKED ||
753                 HIWORD(wParam) == BN_DOUBLECLICKED)
754                 cfg.win_name_always = IsDlgButtonChecked (hwnd, IDC2_WINNAME);
755             break;
756           case IDC2_DECOM:
757             if (HIWORD(wParam) == BN_CLICKED ||
758                 HIWORD(wParam) == BN_DOUBLECLICKED)
759                 cfg.dec_om = IsDlgButtonChecked (hwnd, IDC2_DECOM);
760             break;
761           case IDC2_LFHASCR:
762             if (HIWORD(wParam) == BN_CLICKED ||
763                 HIWORD(wParam) == BN_DOUBLECLICKED)
764                 cfg.lfhascr = IsDlgButtonChecked (hwnd, IDC2_LFHASCR);
765             break;
766           case IDC2_ROWSEDIT:
767             if (HIWORD(wParam) == EN_CHANGE)
768                 MyGetDlgItemInt (hwnd, IDC2_ROWSEDIT, &cfg.height);
769             break;
770           case IDC2_COLSEDIT:
771             if (HIWORD(wParam) == EN_CHANGE)
772                 MyGetDlgItemInt (hwnd, IDC2_COLSEDIT, &cfg.width);
773             break;
774           case IDC2_SAVEEDIT:
775             if (HIWORD(wParam) == EN_CHANGE)
776                 MyGetDlgItemInt (hwnd, IDC2_SAVEEDIT, &cfg.savelines);
777             break;
778           case IDC2_CHOOSEFONT:
779             lf.lfHeight = cfg.fontheight;
780             lf.lfWidth = lf.lfEscapement = lf.lfOrientation = 0;
781             lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = 0;
782             lf.lfWeight = (cfg.fontisbold ? FW_BOLD : 0);
783             lf.lfCharSet = cfg.fontcharset;
784             lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
785             lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
786             lf.lfQuality = DEFAULT_QUALITY;
787             lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
788             strncpy (lf.lfFaceName, cfg.font, sizeof(lf.lfFaceName)-1);
789             lf.lfFaceName[sizeof(lf.lfFaceName)-1] = '\0';
790
791             cf.lStructSize = sizeof(cf);
792             cf.hwndOwner = hwnd;
793             cf.lpLogFont = &lf;
794             cf.Flags = CF_FIXEDPITCHONLY | CF_FORCEFONTEXIST |
795                 CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
796
797             if (ChooseFont (&cf)) {
798                 strncpy (cfg.font, lf.lfFaceName, sizeof(cfg.font)-1);
799                 cfg.font[sizeof(cfg.font)-1] = '\0';
800                 cfg.fontisbold = (lf.lfWeight == FW_BOLD);
801                 cfg.fontcharset = lf.lfCharSet;
802                 cfg.fontheight = lf.lfHeight;
803                 fmtfont (fontstatic);
804                 SetDlgItemText (hwnd, IDC2_FONTSTATIC, fontstatic);
805             }
806             break;
807            case IDC1_BLINKCUR:
808              if (HIWORD(wParam) == BN_CLICKED ||
809                  HIWORD(wParam) == BN_DOUBLECLICKED)
810                  cfg.blink_cur = IsDlgButtonChecked (hwnd, IDC1_BLINKCUR);
811              break;
812            case IDC1_BEEP:
813              if (HIWORD(wParam) == BN_CLICKED ||
814                  HIWORD(wParam) == BN_DOUBLECLICKED)
815                  cfg.beep = IsDlgButtonChecked (hwnd, IDC1_BEEP);
816              break;
817            case IDC2_SCROLLBAR:
818              if (HIWORD(wParam) == BN_CLICKED ||
819                  HIWORD(wParam) == BN_DOUBLECLICKED)
820                  cfg.scrollbar = IsDlgButtonChecked (hwnd, IDC2_SCROLLBAR);
821              break;
822            case IDC2_LOCKSIZE:
823              if (HIWORD(wParam) == BN_CLICKED ||
824                  HIWORD(wParam) == BN_DOUBLECLICKED)
825                  cfg.locksize = IsDlgButtonChecked (hwnd, IDC2_LOCKSIZE);
826              break;
827            case IDC2_BLINKTEXT:
828              if (HIWORD(wParam) == BN_CLICKED ||
829                  HIWORD(wParam) == BN_DOUBLECLICKED)
830                  cfg.blinktext = IsDlgButtonChecked (hwnd, IDC2_BLINKTEXT);
831              break;
832            case IDC2_BCE:
833              if (HIWORD(wParam) == BN_CLICKED ||
834                  HIWORD(wParam) == BN_DOUBLECLICKED)
835                  cfg.bce = IsDlgButtonChecked (hwnd, IDC2_BCE);
836              break;
837         }
838         break;
839     }
840     return GeneralPanelProc (hwnd, msg, wParam, lParam);
841 }
842
843 static int CALLBACK TelnetProc (HWND hwnd, UINT msg,
844                                     WPARAM wParam, LPARAM lParam) {
845     int i;
846
847     switch (msg) {
848       case WM_INITDIALOG:
849         SetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype);
850         SetDlgItemText (hwnd, IDC3_TSEDIT, cfg.termspeed);
851         SetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username);
852         {
853           char *p = cfg.environmt;
854             while (*p) {
855                 SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_ADDSTRING, 0,
856                                     (LPARAM) p);
857                 p += strlen(p)+1;
858             }
859         }
860         CheckRadioButton (hwnd, IDC3_EMBSD, IDC3_EMRFC,
861                           cfg.rfc_environ ? IDC3_EMRFC : IDC3_EMBSD);
862         break;
863       case WM_COMMAND:
864         switch (LOWORD(wParam)) {
865           case IDC3_TTEDIT:
866             if (HIWORD(wParam) == EN_CHANGE)
867             GetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype,
868                             sizeof(cfg.termtype)-1);
869             break;
870           case IDC3_TSEDIT:
871             if (HIWORD(wParam) == EN_CHANGE)
872                 GetDlgItemText (hwnd, IDC3_TSEDIT, cfg.termspeed,
873                                 sizeof(cfg.termspeed)-1);
874             break;
875           case IDC3_LOGEDIT:
876             if (HIWORD(wParam) == EN_CHANGE)
877                 GetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username,
878                                 sizeof(cfg.username)-1);
879             break;
880           case IDC3_EMBSD:
881           case IDC3_EMRFC:
882             cfg.rfc_environ = IsDlgButtonChecked (hwnd, IDC3_EMRFC);
883             break;
884           case IDC3_ENVADD:
885             if (HIWORD(wParam) == BN_CLICKED ||
886                 HIWORD(wParam) == BN_DOUBLECLICKED) {
887               char str[sizeof(cfg.environmt)];
888                 char *p;
889                 GetDlgItemText (hwnd, IDC3_VAREDIT, str, sizeof(str)-1);
890                 if (!*str) {
891                     MessageBeep(0);
892                     break;
893                 }
894                 p = str + strlen(str);
895                 *p++ = '\t';
896                 GetDlgItemText (hwnd, IDC3_VALEDIT, p, sizeof(str)-1-(p-str));
897                 if (!*p) {
898                     MessageBeep(0);
899                     break;
900                 }
901               p = cfg.environmt;
902                 while (*p) {
903                     while (*p) p++;
904                     p++;
905                 }
906               if ((p-cfg.environmt) + strlen(str) + 2 < sizeof(cfg.environmt)) {
907                     strcpy (p, str);
908                     p[strlen(str)+1] = '\0';
909                     SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_ADDSTRING,
910                                         0, (LPARAM)str);
911                     SetDlgItemText (hwnd, IDC3_VAREDIT, "");
912                     SetDlgItemText (hwnd, IDC3_VALEDIT, "");
913                 } else {
914                     MessageBox(hwnd, "Environment too big", "PuTTY Error",
915                                MB_OK | MB_ICONERROR);
916                 }
917             }
918             break;
919           case IDC3_ENVREMOVE:
920             if (HIWORD(wParam) != BN_CLICKED &&
921                 HIWORD(wParam) != BN_DOUBLECLICKED)
922                 break;
923             i = SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_GETCURSEL, 0, 0);
924             if (i == LB_ERR)
925                 MessageBeep (0);
926             else {
927                 char *p, *q;
928
929                 SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_DELETESTRING,
930                                     i, 0);
931               p = cfg.environmt;
932                 while (i > 0) {
933                     if (!*p)
934                         goto disaster;
935                     while (*p) p++;
936                     p++;
937                     i--;
938                 }
939                 q = p;
940                 if (!*p)
941                     goto disaster;
942                 while (*p) p++;
943                 p++;
944                 while (*p) {
945                     while (*p)
946                         *q++ = *p++;
947                     *q++ = *p++;
948                 }
949                 *q = '\0';
950                 disaster:;
951             }
952             break;
953         }
954         break;
955     }
956     return GeneralPanelProc (hwnd, msg, wParam, lParam);
957 }
958
959 static int CALLBACK SshProc (HWND hwnd, UINT msg,
960                              WPARAM wParam, LPARAM lParam) {
961     OPENFILENAME of;
962     char filename[sizeof(cfg.keyfile)];
963
964     switch (msg) {
965       case WM_INITDIALOG:
966         SetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype);
967         SetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username);
968         CheckDlgButton (hwnd, IDC3_NOPTY, cfg.nopty);
969         CheckDlgButton (hwnd, IDC3_AGENTFWD, cfg.agentfwd);
970         CheckRadioButton (hwnd, IDC3_CIPHER3DES, IDC3_CIPHERDES,
971                           cfg.cipher == CIPHER_BLOWFISH ? IDC3_CIPHERBLOWF :
972                           cfg.cipher == CIPHER_DES ? IDC3_CIPHERDES :
973                           IDC3_CIPHER3DES);
974         CheckRadioButton (hwnd, IDC3_SSHPROT1, IDC3_SSHPROT2,
975                           cfg.sshprot == 1 ? IDC3_SSHPROT1 : IDC3_SSHPROT2);
976         CheckDlgButton (hwnd, IDC3_AUTHTIS, cfg.try_tis_auth);
977         SetDlgItemText (hwnd, IDC3_PKEDIT, cfg.keyfile);
978         break;
979       case WM_COMMAND:
980         switch (LOWORD(wParam)) {
981           case IDC3_TTEDIT:
982             if (HIWORD(wParam) == EN_CHANGE)
983             GetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype,
984                             sizeof(cfg.termtype)-1);
985             break;
986           case IDC3_LOGEDIT:
987             if (HIWORD(wParam) == EN_CHANGE)
988                 GetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username,
989                                 sizeof(cfg.username)-1);
990             break;
991           case IDC3_NOPTY:
992             if (HIWORD(wParam) == BN_CLICKED ||
993                 HIWORD(wParam) == BN_DOUBLECLICKED)
994                 cfg.nopty = IsDlgButtonChecked (hwnd, IDC3_NOPTY);
995             break;
996           case IDC3_AGENTFWD:
997             if (HIWORD(wParam) == BN_CLICKED ||
998                 HIWORD(wParam) == BN_DOUBLECLICKED)
999                 cfg.agentfwd = IsDlgButtonChecked (hwnd, IDC3_AGENTFWD);
1000             break;
1001           case IDC3_CIPHER3DES:
1002           case IDC3_CIPHERBLOWF:
1003           case IDC3_CIPHERDES:
1004             if (HIWORD(wParam) == BN_CLICKED ||
1005                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1006                 if (IsDlgButtonChecked (hwnd, IDC3_CIPHER3DES))
1007                     cfg.cipher = CIPHER_3DES;
1008                 else if (IsDlgButtonChecked (hwnd, IDC3_CIPHERBLOWF))
1009                     cfg.cipher = CIPHER_BLOWFISH;
1010                 else if (IsDlgButtonChecked (hwnd, IDC3_CIPHERDES))
1011                     cfg.cipher = CIPHER_DES;
1012             }
1013             break;
1014           case IDC3_SSHPROT1:
1015           case IDC3_SSHPROT2:
1016             if (HIWORD(wParam) == BN_CLICKED ||
1017                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1018                 if (IsDlgButtonChecked (hwnd, IDC3_SSHPROT1))
1019                     cfg.sshprot = 1;
1020                 else if (IsDlgButtonChecked (hwnd, IDC3_SSHPROT2))
1021                     cfg.sshprot = 2;
1022             }
1023             break;
1024           case IDC3_AUTHTIS:
1025             if (HIWORD(wParam) == BN_CLICKED ||
1026                 HIWORD(wParam) == BN_DOUBLECLICKED)
1027                 cfg.try_tis_auth = IsDlgButtonChecked (hwnd, IDC3_AUTHTIS);
1028             break;
1029           case IDC3_PKEDIT:
1030             if (HIWORD(wParam) == EN_CHANGE)
1031                 GetDlgItemText (hwnd, IDC3_PKEDIT, cfg.keyfile,
1032                                 sizeof(cfg.keyfile)-1);
1033             break;
1034           case IDC3_PKBUTTON:
1035             /*
1036              * FIXME: this crashes. Find out why.
1037              */
1038             memset(&of, 0, sizeof(of));
1039 #ifdef OPENFILENAME_SIZE_VERSION_400
1040             of.lStructSize = OPENFILENAME_SIZE_VERSION_400;
1041 #else
1042             of.lStructSize = sizeof(of);
1043 #endif
1044             of.hwndOwner = hwnd;
1045             of.lpstrFilter = "All Files\0*\0\0\0";
1046             of.lpstrCustomFilter = NULL;
1047             of.nFilterIndex = 1;
1048             of.lpstrFile = filename; strcpy(filename, cfg.keyfile);
1049             of.nMaxFile = sizeof(filename);
1050             of.lpstrFileTitle = NULL;
1051             of.lpstrInitialDir = NULL;
1052             of.lpstrTitle = "Select Public Key File";
1053             of.Flags = 0;
1054             if (GetOpenFileName(&of)) {
1055                 strcpy(cfg.keyfile, filename);
1056                 SetDlgItemText (hwnd, IDC3_PKEDIT, cfg.keyfile);
1057             }
1058             break;
1059         }
1060         break;
1061     }
1062     return GeneralPanelProc (hwnd, msg, wParam, lParam);
1063 }
1064
1065 static int CALLBACK SelectionProc (HWND hwnd, UINT msg,
1066                                     WPARAM wParam, LPARAM lParam) {
1067     int i;
1068
1069     switch (msg) {
1070       case WM_INITDIALOG:
1071         CheckRadioButton (hwnd, IDC4_MBWINDOWS, IDC4_MBXTERM,
1072                           cfg.mouse_is_xterm ? IDC4_MBXTERM : IDC4_MBWINDOWS);
1073         {
1074             static int tabs[4] = {25, 61, 96, 128};
1075             SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_SETTABSTOPS, 4,
1076                                 (LPARAM) tabs);
1077         }
1078         for (i=0; i<256; i++) {
1079             char str[100];
1080             sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
1081                     (i>=0x21 && i != 0x7F) ? i : ' ',
1082                     cfg.wordness[i]);
1083             SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_ADDSTRING, 0,
1084                                 (LPARAM) str);
1085         }
1086         break;
1087       case WM_COMMAND:
1088         switch (LOWORD(wParam)) {
1089           case IDC4_MBWINDOWS:
1090           case IDC4_MBXTERM:
1091             cfg.mouse_is_xterm = IsDlgButtonChecked (hwnd, IDC4_MBXTERM);
1092             break;
1093           case IDC4_CCSET:
1094             {
1095                 BOOL ok;
1096                 int i;
1097                 int n = GetDlgItemInt (hwnd, IDC4_CCEDIT, &ok, FALSE);
1098
1099                 if (!ok)
1100                     MessageBeep (0);
1101                 else {
1102                     for (i=0; i<256; i++)
1103                         if (SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_GETSEL,
1104                                                 i, 0)) {
1105                             char str[100];
1106                             cfg.wordness[i] = n;
1107                             SendDlgItemMessage (hwnd, IDC4_CCLIST,
1108                                                 LB_DELETESTRING, i, 0);
1109                             sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
1110                                     (i>=0x21 && i != 0x7F) ? i : ' ',
1111                                     cfg.wordness[i]);
1112                             SendDlgItemMessage (hwnd, IDC4_CCLIST,
1113                                                 LB_INSERTSTRING, i,
1114                                                 (LPARAM)str);
1115                         }
1116                 }
1117             }
1118             break;
1119         }
1120         break;
1121     }
1122     return GeneralPanelProc (hwnd, msg, wParam, lParam);
1123 }
1124
1125 static int CALLBACK ColourProc (HWND hwnd, UINT msg,
1126                                     WPARAM wParam, LPARAM lParam) {
1127     static const char *const colours[] = {
1128         "Default Foreground", "Default Bold Foreground",
1129         "Default Background", "Default Bold Background",
1130         "Cursor Text", "Cursor Colour",
1131         "ANSI Black", "ANSI Black Bold",
1132         "ANSI Red", "ANSI Red Bold",
1133         "ANSI Green", "ANSI Green Bold",
1134         "ANSI Yellow", "ANSI Yellow Bold",
1135         "ANSI Blue", "ANSI Blue Bold",
1136         "ANSI Magenta", "ANSI Magenta Bold",
1137         "ANSI Cyan", "ANSI Cyan Bold",
1138         "ANSI White", "ANSI White Bold"
1139     };
1140     static const int permanent[] = {
1141         TRUE, FALSE, TRUE, FALSE, TRUE, TRUE,
1142         TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE,
1143         TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE
1144     };
1145     switch (msg) {
1146       case WM_INITDIALOG:
1147         CheckDlgButton (hwnd, IDC5_BOLDCOLOUR, cfg.bold_colour);
1148         CheckDlgButton (hwnd, IDC5_PALETTE, cfg.try_palette);
1149         {
1150             int i;
1151             for (i=0; i<22; i++)
1152                 if (cfg.bold_colour || permanent[i])
1153                     SendDlgItemMessage (hwnd, IDC5_LIST, LB_ADDSTRING, 0,
1154                                         (LPARAM) colours[i]);
1155         }
1156         SendDlgItemMessage (hwnd, IDC5_LIST, LB_SETCURSEL, 0, 0);
1157         SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[0][0], FALSE);
1158         SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[0][1], FALSE);
1159         SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[0][2], FALSE);
1160         break;
1161       case WM_COMMAND:
1162         switch (LOWORD(wParam)) {
1163           case IDC5_BOLDCOLOUR:
1164             if (HIWORD(wParam) == BN_CLICKED ||
1165                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1166                 int n, i;
1167                 cfg.bold_colour = IsDlgButtonChecked (hwnd, IDC5_BOLDCOLOUR);
1168                 n = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCOUNT, 0, 0);
1169                 if (cfg.bold_colour && n!=22) {
1170                     for (i=0; i<22; i++)
1171                         if (!permanent[i])
1172                             SendDlgItemMessage (hwnd, IDC5_LIST,
1173                                                 LB_INSERTSTRING, i,
1174                                                 (LPARAM) colours[i]);
1175                 } else if (!cfg.bold_colour && n!=12) {
1176                     for (i=22; i-- ;)
1177                         if (!permanent[i])
1178                             SendDlgItemMessage (hwnd, IDC5_LIST,
1179                                                 LB_DELETESTRING, i, 0);
1180                 }
1181             }
1182             break;
1183           case IDC5_PALETTE:
1184             if (HIWORD(wParam) == BN_CLICKED ||
1185                 HIWORD(wParam) == BN_DOUBLECLICKED)
1186                 cfg.try_palette = IsDlgButtonChecked (hwnd, IDC5_PALETTE);
1187             break;
1188           case IDC5_LIST:
1189             if (HIWORD(wParam) == LBN_DBLCLK ||
1190                 HIWORD(wParam) == LBN_SELCHANGE) {
1191                 int i = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCURSEL,
1192                                             0, 0);
1193                 if (!cfg.bold_colour)
1194                     i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
1195                 SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[i][0], FALSE);
1196                 SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[i][1], FALSE);
1197                 SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[i][2], FALSE);
1198             }
1199             break;
1200           case IDC5_CHANGE:
1201             if (HIWORD(wParam) == BN_CLICKED ||
1202                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1203                 static CHOOSECOLOR cc;
1204                 static DWORD custom[16] = {0};   /* zero initialisers */
1205                 int i = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCURSEL,
1206                                             0, 0);
1207                 if (!cfg.bold_colour)
1208                     i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
1209                 cc.lStructSize = sizeof(cc);
1210                 cc.hwndOwner = hwnd;
1211                 cc.hInstance = (HWND)hinst;
1212                 cc.lpCustColors = custom;
1213                 cc.rgbResult = RGB (cfg.colours[i][0], cfg.colours[i][1],
1214                                     cfg.colours[i][2]);
1215                 cc.Flags = CC_FULLOPEN | CC_RGBINIT;
1216                 if (ChooseColor(&cc)) {
1217                     cfg.colours[i][0] =
1218                         (unsigned char) (cc.rgbResult & 0xFF);
1219                     cfg.colours[i][1] =
1220                         (unsigned char) (cc.rgbResult >> 8) & 0xFF;
1221                     cfg.colours[i][2] =
1222                         (unsigned char) (cc.rgbResult >> 16) & 0xFF;
1223                     SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[i][0],
1224                                    FALSE);
1225                     SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[i][1],
1226                                    FALSE);
1227                     SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[i][2],
1228                                    FALSE);
1229                 }
1230             }
1231             break;
1232         }
1233         break;
1234     }
1235     return GeneralPanelProc (hwnd, msg, wParam, lParam);
1236 }
1237
1238 static int CALLBACK TranslationProc (HWND hwnd, UINT msg,
1239                                   WPARAM wParam, LPARAM lParam) {
1240     switch (msg) {
1241       case WM_INITDIALOG:
1242         CheckRadioButton (hwnd, IDC6_NOXLAT, IDC6_88592WIN1250,
1243                           cfg.xlat_88592w1250 ? IDC6_88592WIN1250 :
1244                           cfg.xlat_enablekoiwin ? IDC6_KOI8WIN1251 :
1245                           IDC6_NOXLAT);
1246         CheckDlgButton (hwnd, IDC6_CAPSLOCKCYR, cfg.xlat_capslockcyr);
1247         CheckRadioButton (hwnd, IDC2_VTXWINDOWS, IDC2_VTPOORMAN,
1248                           cfg.vtmode == VT_XWINDOWS ? IDC2_VTXWINDOWS :
1249                           cfg.vtmode == VT_OEMANSI ? IDC2_VTOEMANSI :
1250                           cfg.vtmode == VT_OEMONLY ? IDC2_VTOEMONLY :
1251                           IDC2_VTPOORMAN);
1252       case WM_COMMAND:
1253         switch (LOWORD(wParam)) {
1254           case IDC6_NOXLAT:
1255           case IDC6_KOI8WIN1251:
1256           case IDC6_88592WIN1250:
1257             cfg.xlat_enablekoiwin =
1258                 IsDlgButtonChecked (hwnd, IDC6_KOI8WIN1251);
1259             cfg.xlat_88592w1250 =
1260                 IsDlgButtonChecked (hwnd, IDC6_88592WIN1250);
1261             break;
1262           case IDC6_CAPSLOCKCYR:
1263             if (HIWORD(wParam) == BN_CLICKED ||
1264                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1265                 cfg.xlat_capslockcyr =
1266                     IsDlgButtonChecked (hwnd, IDC6_CAPSLOCKCYR);
1267             }
1268             break;
1269           case IDC2_VTXWINDOWS:
1270           case IDC2_VTOEMANSI:
1271           case IDC2_VTOEMONLY:
1272           case IDC2_VTPOORMAN:
1273             cfg.vtmode =
1274                 (IsDlgButtonChecked (hwnd, IDC2_VTXWINDOWS) ? VT_XWINDOWS :
1275                  IsDlgButtonChecked (hwnd, IDC2_VTOEMANSI) ? VT_OEMANSI :
1276                  IsDlgButtonChecked (hwnd, IDC2_VTOEMONLY) ? VT_OEMONLY :
1277                  VT_POORMAN);
1278             break;
1279         }
1280     }
1281     return GeneralPanelProc (hwnd, msg, wParam, lParam);
1282 }
1283
1284 static DLGPROC panelproc[NPANELS] = {
1285     ConnectionProc, KeyboardProc, TerminalProc,
1286     TelnetProc, SshProc, SelectionProc, ColourProc, TranslationProc
1287 };
1288 static char *panelids[NPANELS] = {
1289     MAKEINTRESOURCE(IDD_PANEL0),
1290     MAKEINTRESOURCE(IDD_PANEL1),
1291     MAKEINTRESOURCE(IDD_PANEL2),
1292     MAKEINTRESOURCE(IDD_PANEL3),
1293     MAKEINTRESOURCE(IDD_PANEL35),
1294     MAKEINTRESOURCE(IDD_PANEL4),
1295     MAKEINTRESOURCE(IDD_PANEL5),
1296     MAKEINTRESOURCE(IDD_PANEL6)
1297 };
1298
1299 static char *names[NPANELS] = {
1300     "Connection", "Keyboard", "Terminal", "Telnet",
1301     "SSH", "Selection", "Colours", "Translation"
1302 };
1303
1304 static int mainp[MAIN_NPANELS] = { 0, 1, 2, 3, 4, 5, 6, 7};
1305 static int reconfp[RECONF_NPANELS] = { 1, 2, 5, 6, 7};
1306
1307 static int GenericMainDlgProc (HWND hwnd, UINT msg,
1308                                WPARAM wParam, LPARAM lParam,
1309                                int npanels, int *panelnums, HWND *page) {
1310     HWND hw;
1311
1312     switch (msg) {
1313       case WM_INITDIALOG:
1314         {                              /* centre the window */
1315             RECT rs, rd;
1316
1317             hw = GetDesktopWindow();
1318             if (GetWindowRect (hw, &rs) && GetWindowRect (hwnd, &rd))
1319                 MoveWindow (hwnd, (rs.right + rs.left + rd.left - rd.right)/2,
1320                             (rs.bottom + rs.top + rd.top - rd.bottom)/2,
1321                             rd.right-rd.left, rd.bottom-rd.top, TRUE);
1322         }
1323         *page = NULL;
1324         {                              /* initialise the tab control */
1325             TC_ITEMHEADER tab;
1326             int i;
1327
1328             hw = GetDlgItem (hwnd, IDC_TAB);
1329             for (i=0; i<npanels; i++) {
1330                 tab.mask = TCIF_TEXT;
1331                 tab.pszText = names[panelnums[i]];
1332                 TabCtrl_InsertItem (hw, i, &tab);
1333             }
1334 /*          *page = CreateDialogIndirect (hinst, panels[panelnums[0]].temp,
1335                                           hwnd, panelproc[panelnums[0]]);*/
1336             *page = CreateDialog (hinst, panelids[panelnums[0]],
1337                                   hwnd, panelproc[panelnums[0]]);
1338             SetWindowLong (*page, GWL_EXSTYLE,
1339                            GetWindowLong (*page, GWL_EXSTYLE) |
1340                            WS_EX_CONTROLPARENT);
1341         }
1342         SetFocus (*page);
1343         return 0;
1344       case WM_NOTIFY:
1345         if (LOWORD(wParam) == IDC_TAB &&
1346             ((LPNMHDR)lParam)->code == TCN_SELCHANGE) {
1347             int i = TabCtrl_GetCurSel(((LPNMHDR)lParam)->hwndFrom);
1348             if (*page)
1349                 DestroyWindow (*page);
1350 /*          *page = CreateDialogIndirect (hinst, panels[panelnums[i]].temp,     
1351                                           hwnd, panelproc[panelnums[i]]);*/
1352             *page = CreateDialog (hinst, panelids[panelnums[i]],
1353                                   hwnd, panelproc[panelnums[i]]);
1354             SetWindowLong (*page, GWL_EXSTYLE,
1355                            GetWindowLong (*page, GWL_EXSTYLE) |
1356                            WS_EX_CONTROLPARENT);
1357             SetFocus (((LPNMHDR)lParam)->hwndFrom);   /* ensure focus stays */
1358             return 0;
1359         }
1360         break;
1361 /*      case WM_CTLCOLORDLG: */
1362 /*      return (int) GetStockObject (LTGRAY_BRUSH); */
1363       case WM_COMMAND:
1364         switch (LOWORD(wParam)) {
1365           case IDOK:
1366             if (*cfg.host)
1367                 EndDialog (hwnd, 1);
1368             else
1369                 MessageBeep (0);
1370             return 0;
1371           case IDCANCEL:
1372             EndDialog (hwnd, 0);
1373             return 0;
1374         }
1375         return 0;
1376       case WM_CLOSE:
1377         EndDialog (hwnd, 0);
1378         return 0;
1379
1380         /* Grrr Explorer will maximize Dialogs! */
1381       case WM_SIZE:
1382         if (wParam == SIZE_MAXIMIZED)
1383            force_normal(hwnd);
1384         return 0;
1385     }
1386     return 0;
1387 }
1388
1389 static int CALLBACK MainDlgProc (HWND hwnd, UINT msg,
1390                                  WPARAM wParam, LPARAM lParam) {
1391 #if 0
1392     HWND hw;
1393     int i;
1394 #endif
1395     static HWND page = NULL;
1396
1397     if (msg == WM_COMMAND && LOWORD(wParam) == IDOK) {
1398 #if 0
1399         /*
1400          * If the Connection panel is active and the Session List
1401          * box is selected, we treat a press of Open to have an
1402          * implicit press of Load preceding it.
1403          */
1404         hw = GetDlgItem (hwnd, IDC_TAB);
1405         i = TabCtrl_GetCurSel(hw);
1406         if (panelproc[mainp[i]] == ConnectionProc &&
1407             page && implicit_load_ok) {
1408             SendMessage (page, WM_COMMAND,
1409                          MAKELONG(IDC0_SESSLOAD, BN_CLICKED), 0);
1410         }
1411 #endif
1412     }
1413     if (msg == WM_COMMAND && LOWORD(wParam) == IDC_ABOUT) {
1414         EnableWindow(hwnd, 0);
1415         DialogBox(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
1416                   GetParent(hwnd), AboutProc);
1417         EnableWindow(hwnd, 1);
1418         SetActiveWindow(hwnd);
1419     }
1420     return GenericMainDlgProc (hwnd, msg, wParam, lParam,
1421                                MAIN_NPANELS, mainp, &page);
1422 }
1423
1424 static int CALLBACK ReconfDlgProc (HWND hwnd, UINT msg,
1425                                    WPARAM wParam, LPARAM lParam) {
1426     static HWND page;
1427     return GenericMainDlgProc (hwnd, msg, wParam, lParam,
1428                                RECONF_NPANELS, reconfp, &page);
1429 }
1430
1431 void get_sesslist(int allocate) {
1432     static char otherbuf[2048];
1433     static char *buffer;
1434     int buflen, bufsize, i;
1435     char *p, *ret;
1436     void *handle;
1437
1438     if (allocate) {
1439         
1440         if ((handle = enum_settings_start()) == NULL)
1441             return;
1442
1443         buflen = bufsize = 0;
1444         buffer = NULL;
1445         do {
1446             ret = enum_settings_next(handle, otherbuf, sizeof(otherbuf));
1447             if (ret) {
1448                 int len = strlen(otherbuf)+1;
1449                 if (bufsize < buflen+len) {
1450                     bufsize = buflen + len + 2048;
1451                     buffer = srealloc(buffer, bufsize);
1452                 }
1453                 strcpy(buffer+buflen, otherbuf);
1454                 buflen += strlen(buffer+buflen)+1;
1455             }
1456         } while (ret);
1457         enum_settings_finish(handle);
1458         buffer = srealloc(buffer, buflen+1);
1459         buffer[buflen] = '\0';
1460
1461         p = buffer;
1462         nsessions = 1;                 /* "Default Settings" counts as one */
1463         while (*p) {
1464             if (strcmp(p, "Default Settings"))
1465                 nsessions++;
1466             while (*p) p++;
1467             p++;
1468         }
1469
1470         sessions = smalloc(nsessions * sizeof(char *));
1471         sessions[0] = "Default Settings";
1472         p = buffer;
1473         i = 1;
1474         while (*p) {
1475             if (strcmp(p, "Default Settings"))
1476                 sessions[i++] = p;
1477             while (*p) p++;
1478             p++;
1479         }
1480     } else {
1481         sfree (buffer);
1482         sfree (sessions);
1483     }
1484 }
1485
1486 int do_config (void) {
1487     int ret;
1488
1489     get_sesslist(TRUE);
1490     savedsession[0] = '\0';
1491     ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_MAINBOX), NULL, MainDlgProc);
1492     get_sesslist(FALSE);
1493
1494     return ret;
1495 }
1496
1497 int do_reconfig (HWND hwnd) {
1498     Config backup_cfg;
1499     int ret;
1500
1501     backup_cfg = cfg;                  /* structure copy */
1502     ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_RECONF), hwnd, ReconfDlgProc);
1503     if (!ret)
1504         cfg = backup_cfg;              /* structure copy */
1505     else
1506         force_normal(hwnd);
1507
1508     return ret;
1509 }
1510
1511 void do_defaults (char *session) {
1512     if (session)
1513         load_settings (session, TRUE);
1514     else
1515         load_settings ("Default Settings", FALSE);
1516 }
1517
1518 void logevent (char *string) {
1519     if (nevents >= negsize) {
1520         negsize += 64;
1521         events = srealloc (events, negsize * sizeof(*events));
1522     }
1523     events[nevents] = smalloc(1+strlen(string));
1524     strcpy (events[nevents], string);
1525     nevents++;
1526     if (logbox) {
1527         int count;
1528         SendDlgItemMessage (logbox, IDN_LIST, LB_ADDSTRING,
1529                             0, (LPARAM)string);
1530         count = SendDlgItemMessage (logbox, IDN_LIST, LB_GETCOUNT, 0, 0);
1531         SendDlgItemMessage (logbox, IDN_LIST, LB_SETTOPINDEX, count-1, 0);
1532     }
1533 }
1534
1535 void showeventlog (HWND hwnd) {
1536     if (!logbox) {
1537         logbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_LOGBOX),
1538                                hwnd, LogProc);
1539         ShowWindow (logbox, SW_SHOWNORMAL);
1540     }
1541 }
1542
1543 void showabout (HWND hwnd) {
1544     if (!abtbox) {
1545         abtbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
1546                                hwnd, AboutProc);
1547         ShowWindow (abtbox, SW_SHOWNORMAL);
1548     }
1549 }
1550
1551 void verify_ssh_host_key(char *host, int port, char *keytype,
1552                          char *keystr, char *fingerprint) {
1553     int ret;
1554
1555     static const char absentmsg[] =
1556         "The server's host key is not cached in the registry. You\n"
1557         "have no guarantee that the server is the computer you\n"
1558         "think it is.\n"
1559         "The server's key fingerprint is:\n"
1560         "%s\n"
1561         "If you trust this host, hit Yes to add the key to\n"
1562         "PuTTY's cache and carry on connecting.\n"
1563         "If you do not trust this host, hit No to abandon the\n"
1564         "connection.\n";
1565
1566     static const char wrongmsg[] =
1567         "WARNING - POTENTIAL SECURITY BREACH!\n"
1568         "\n"
1569         "The server's host key does not match the one PuTTY has\n"
1570         "cached in the registry. This means that either the\n"
1571         "server administrator has changed the host key, or you\n"
1572         "have actually connected to another computer pretending\n"
1573         "to be the server.\n"
1574         "The new key fingerprint is:\n"
1575         "%s\n"
1576         "If you were expecting this change and trust the new key,\n"
1577         "hit Yes to update PuTTY's cache and continue connecting.\n"
1578         "If you want to carry on connecting but without updating\n"
1579         "the cache, hit No.\n"
1580         "If you want to abandon the connection completely, hit\n"
1581         "Cancel. Hitting Cancel is the ONLY guaranteed safe\n"
1582         "choice.\n";
1583
1584     static const char mbtitle[] = "PuTTY Security Alert";
1585
1586     
1587     char message[160+                  /* sensible fingerprint max size */
1588                  (sizeof(absentmsg) > sizeof(wrongmsg) ?
1589                   sizeof(absentmsg) : sizeof(wrongmsg))];
1590
1591     /*
1592      * Verify the key against the registry.
1593      */
1594     ret = verify_host_key(host, port, keytype, keystr);
1595
1596     if (ret == 0)                      /* success - key matched OK */
1597         return;
1598     if (ret == 2) {                    /* key was different */
1599         int mbret;
1600         sprintf(message, wrongmsg, fingerprint);
1601         mbret = MessageBox(NULL, message, mbtitle,
1602                            MB_ICONWARNING | MB_YESNOCANCEL);
1603         if (mbret == IDYES)
1604             store_host_key(host, port, keytype, keystr);
1605         if (mbret == IDCANCEL)
1606             exit(0);
1607     }
1608     if (ret == 1) {                    /* key was absent */
1609         int mbret;
1610         sprintf(message, absentmsg, fingerprint);
1611         mbret = MessageBox(NULL, message, mbtitle,
1612                            MB_ICONWARNING | MB_YESNO);
1613         if (mbret == IDNO)
1614             exit(0);
1615         store_host_key(host, port, keytype, keystr);
1616     }
1617 }