]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - windlg.c
89aecba0f01da97f77cdf266195e4bd2d821ae71
[PuTTY.git] / windlg.c
1 #include <windows.h>
2 #include <commctrl.h>
3 #include <commdlg.h>
4 #ifndef AUTO_WINSOCK
5 #ifdef WINSOCK_TWO
6 #include <winsock2.h>
7 #else
8 #include <winsock.h>
9 #endif
10 #endif
11 #include <stdio.h>
12 #include <stdlib.h>
13
14 #include "ssh.h"
15 #include "putty.h"
16 #include "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             abtbox = NULL;
396             DestroyWindow (hwnd);
397             return 0;
398         }
399         return 0;
400       case WM_CLOSE:
401         abtbox = NULL;
402         DestroyWindow (hwnd);
403         return 0;
404     }
405     return 0;
406 }
407
408 static int CALLBACK AboutProc (HWND hwnd, UINT msg,
409                                WPARAM wParam, LPARAM lParam) {
410     switch (msg) {
411       case WM_INITDIALOG:
412         SetDlgItemText (hwnd, IDA_VERSION, ver);
413         return 1;
414 /*      case WM_CTLCOLORDLG: */
415 /*      return (int) GetStockObject (LTGRAY_BRUSH); */
416 /*      case WM_CTLCOLORSTATIC: */
417 /*      SetBkColor ((HDC)wParam, RGB(192,192,192)); */
418 /*      return (int) GetStockObject (LTGRAY_BRUSH); */
419       case WM_COMMAND:
420         switch (LOWORD(wParam)) {
421           case IDOK:
422             abtbox = NULL;
423             DestroyWindow (hwnd);
424             return 0;
425           case IDA_LICENCE:
426             EnableWindow(hwnd, 0);
427             DialogBox (hinst, MAKEINTRESOURCE(IDD_LICENCEBOX),
428                        NULL, LicenceProc);
429             EnableWindow(hwnd, 1);
430             SetActiveWindow(hwnd);
431             return 0;
432         }
433         return 0;
434       case WM_CLOSE:
435         abtbox = NULL;
436         DestroyWindow (hwnd);
437         return 0;
438     }
439     return 0;
440 }
441
442 static int GeneralPanelProc (HWND hwnd, UINT msg,
443                              WPARAM wParam, LPARAM lParam) {
444     switch (msg) {
445       case WM_INITDIALOG:
446         SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
447         return 1;
448 /*      case WM_CTLCOLORDLG: */
449 /*      return (int) GetStockObject (LTGRAY_BRUSH); */
450 /*      case WM_CTLCOLORSTATIC: */
451 /*      case WM_CTLCOLORBTN: */
452 /*      SetBkColor ((HDC)wParam, RGB(192,192,192)); */
453 /*      return (int) GetStockObject (LTGRAY_BRUSH); */
454       case WM_CLOSE:
455         DestroyWindow (hwnd);
456         return 1;
457     }
458     return 0;
459 }
460
461 static char savedsession[2048];
462
463 static int CALLBACK ConnectionProc (HWND hwnd, UINT msg,
464                                     WPARAM wParam, LPARAM lParam) {
465     int i;
466
467     switch (msg) {
468       case WM_INITDIALOG:
469         SetDlgItemText (hwnd, IDC0_HOST, cfg.host);
470         SetDlgItemText (hwnd, IDC0_SESSEDIT, savedsession);
471         SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE);
472         for (i = 0; i < nsessions; i++)
473             SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING,
474                                 0, (LPARAM) (sessions[i]));
475         CheckRadioButton (hwnd, IDC0_PROTRAW, IDC0_PROTSSH,
476                           cfg.protocol==PROT_SSH ? IDC0_PROTSSH : 
477                           cfg.protocol==PROT_TELNET ? IDC0_PROTTELNET : IDC0_PROTRAW );
478         CheckDlgButton (hwnd, IDC0_CLOSEEXIT, cfg.close_on_exit);
479         CheckDlgButton (hwnd, IDC0_CLOSEWARN, cfg.warn_on_close);
480         break;
481       case WM_LBUTTONUP:
482         /*
483          * Button release should trigger WM_OK if there was a
484          * previous double click on the session list.
485          */
486         ReleaseCapture();
487         if (readytogo)
488             SendMessage (GetParent(hwnd), WM_COMMAND, IDOK, 0);
489         break;
490       case WM_COMMAND:
491         switch (LOWORD(wParam)) {
492           case IDC0_PROTTELNET:
493           case IDC0_PROTSSH:
494           case IDC0_PROTRAW:
495             if (HIWORD(wParam) == BN_CLICKED ||
496                 HIWORD(wParam) == BN_DOUBLECLICKED) {
497                 int i = IsDlgButtonChecked (hwnd, IDC0_PROTSSH);
498                 int j = IsDlgButtonChecked (hwnd, IDC0_PROTTELNET);
499                 cfg.protocol = i ? PROT_SSH : j ? PROT_TELNET : PROT_RAW ;
500                 if ((cfg.protocol == PROT_SSH && cfg.port == 23) ||
501                     (cfg.protocol == PROT_TELNET && cfg.port == 22)) {
502                     cfg.port = i ? 22 : 23;
503                     SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE);
504                 }
505             }
506             break;
507           case IDC0_HOST:
508             if (HIWORD(wParam) == EN_CHANGE)
509                 GetDlgItemText (hwnd, IDC0_HOST, cfg.host,
510                                 sizeof(cfg.host)-1);
511             break;
512           case IDC0_PORT:
513             if (HIWORD(wParam) == EN_CHANGE)
514                 MyGetDlgItemInt (hwnd, IDC0_PORT, &cfg.port);
515             break;
516           case IDC0_CLOSEEXIT:
517             if (HIWORD(wParam) == BN_CLICKED ||
518                 HIWORD(wParam) == BN_DOUBLECLICKED)
519                 cfg.close_on_exit = IsDlgButtonChecked (hwnd, IDC0_CLOSEEXIT);
520             break;
521           case IDC0_CLOSEWARN:
522             if (HIWORD(wParam) == BN_CLICKED ||
523                 HIWORD(wParam) == BN_DOUBLECLICKED)
524                 cfg.warn_on_close = IsDlgButtonChecked (hwnd, IDC0_CLOSEWARN);
525             break;
526           case IDC0_SESSEDIT:
527             if (HIWORD(wParam) == EN_CHANGE) {
528                 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
529                                     (WPARAM) -1, 0);
530                 GetDlgItemText (hwnd, IDC0_SESSEDIT,
531                                 savedsession, sizeof(savedsession)-1);
532                 savedsession[sizeof(savedsession)-1] = '\0';
533             }
534             break;
535           case IDC0_SESSSAVE:
536             if (HIWORD(wParam) == BN_CLICKED ||
537                 HIWORD(wParam) == BN_DOUBLECLICKED) {
538                 /*
539                  * Save a session
540                  */
541                 char str[2048];
542                 GetDlgItemText (hwnd, IDC0_SESSEDIT, str, sizeof(str)-1);
543                 if (!*str) {
544                     int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
545                                                 LB_GETCURSEL, 0, 0);
546                     if (n == LB_ERR) {
547                         MessageBeep(0);
548                         break;
549                     }
550                     strcpy (str, sessions[n]);
551                 }
552                 save_settings (str, !!strcmp(str, "Default Settings"));
553                 get_sesslist (FALSE);
554                 get_sesslist (TRUE);
555                 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_RESETCONTENT,
556                                     0, 0);
557                 for (i = 0; i < nsessions; i++)
558                     SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING,
559                                         0, (LPARAM) (sessions[i]));
560                 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
561                                     (WPARAM) -1, 0);
562             }
563             break;
564           case IDC0_SESSLIST:
565           case IDC0_SESSLOAD:
566             if (LOWORD(wParam) == IDC0_SESSLOAD &&
567                 HIWORD(wParam) != BN_CLICKED &&
568                 HIWORD(wParam) != BN_DOUBLECLICKED)
569                 break;
570             if (LOWORD(wParam) == IDC0_SESSLIST &&
571                 HIWORD(wParam) != LBN_DBLCLK)
572                 break;
573             {
574                 int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
575                                             LB_GETCURSEL, 0, 0);
576                 if (n == LB_ERR) {
577                     MessageBeep(0);
578                     break;
579                 }
580                 load_settings (sessions[n],
581                                !!strcmp(sessions[n], "Default Settings"));
582                 SetDlgItemText (hwnd, IDC0_HOST, cfg.host);
583                 SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE);
584                 CheckRadioButton (hwnd, IDC0_PROTRAW, IDC0_PROTSSH,
585                                   (cfg.protocol==PROT_SSH ? IDC0_PROTSSH :
586                                   cfg.protocol==PROT_TELNET ? IDC0_PROTTELNET : IDC0_PROTRAW));
587                 CheckDlgButton (hwnd, IDC0_CLOSEEXIT, cfg.close_on_exit);
588                 CheckDlgButton (hwnd, IDC0_CLOSEWARN, cfg.warn_on_close);
589                 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
590                                     (WPARAM) -1, 0);
591             }
592             if (LOWORD(wParam) == IDC0_SESSLIST) {
593                 /*
594                  * A double-click on a saved session should
595                  * actually start the session, not just load it.
596                  * Unless it's Default Settings or some other
597                  * host-less set of saved settings.
598                  */
599                 if (*cfg.host) {
600                     readytogo = TRUE;
601                     SetCapture(hwnd);
602                 }
603             }
604             break;
605           case IDC0_SESSDEL:
606             if (HIWORD(wParam) == BN_CLICKED ||
607                 HIWORD(wParam) == BN_DOUBLECLICKED) {
608                 int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
609                                             LB_GETCURSEL, 0, 0);
610                 if (n == LB_ERR || n == 0) {
611                     MessageBeep(0);
612                     break;
613                 }
614                 del_settings(sessions[n]);
615                 get_sesslist (FALSE);
616                 get_sesslist (TRUE);
617                 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_RESETCONTENT,
618                                     0, 0);
619                 for (i = 0; i < nsessions; i++)
620                     SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING,
621                                         0, (LPARAM) (sessions[i]));
622                 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
623                                     (WPARAM) -1, 0);
624             }
625         }
626     }
627     return GeneralPanelProc (hwnd, msg, wParam, lParam);
628 }
629
630 static int CALLBACK KeyboardProc (HWND hwnd, UINT msg,
631                                     WPARAM wParam, LPARAM lParam) {
632     switch (msg) {
633       case WM_INITDIALOG:
634         CheckRadioButton (hwnd, IDC1_DEL008, IDC1_DEL127,
635                           cfg.bksp_is_delete ? IDC1_DEL127 : IDC1_DEL008);
636         CheckRadioButton (hwnd, IDC1_HOMETILDE, IDC1_HOMERXVT,
637                           cfg.rxvt_homeend ? IDC1_HOMERXVT : IDC1_HOMETILDE);
638         CheckRadioButton (hwnd, IDC1_FUNCTILDE, IDC1_FUNCXTERM,
639                           cfg.funky_type ? 
640                           (cfg.funky_type==2 ? IDC1_FUNCXTERM 
641                            : IDC1_FUNCLINUX )
642                           : IDC1_FUNCTILDE);
643         CheckRadioButton (hwnd, IDC1_CURNORMAL, IDC1_CURAPPLIC,
644                           cfg.app_cursor ? IDC1_CURAPPLIC : IDC1_CURNORMAL);
645         CheckRadioButton (hwnd, IDC1_KPNORMAL, IDC1_KPNH,
646                           cfg.nethack_keypad ? IDC1_KPNH :
647                           cfg.app_keypad ? IDC1_KPAPPLIC : IDC1_KPNORMAL);
648         CheckDlgButton (hwnd, IDC1_ALTF4, cfg.alt_f4);
649         CheckDlgButton (hwnd, IDC1_ALTSPACE, cfg.alt_space);
650         CheckDlgButton (hwnd, IDC1_LDISCTERM, cfg.ldisc_term);
651         CheckDlgButton (hwnd, IDC1_SCROLLKEY, cfg.scroll_on_key);
652         break;
653       case WM_COMMAND:
654         if (HIWORD(wParam) == BN_CLICKED ||
655             HIWORD(wParam) == BN_DOUBLECLICKED)
656             switch (LOWORD(wParam)) {
657               case IDC1_DEL008:
658               case IDC1_DEL127:
659                 cfg.bksp_is_delete = IsDlgButtonChecked (hwnd, IDC1_DEL127);
660                 break;
661               case IDC1_HOMETILDE:
662               case IDC1_HOMERXVT:
663                 cfg.rxvt_homeend = IsDlgButtonChecked (hwnd, IDC1_HOMERXVT);
664                 break;
665               case IDC1_FUNCXTERM:
666                 cfg.funky_type = 2;
667                 break;
668               case IDC1_FUNCTILDE:
669               case IDC1_FUNCLINUX:
670                 cfg.funky_type = IsDlgButtonChecked (hwnd, IDC1_FUNCLINUX);
671                 break;
672               case IDC1_KPNORMAL:
673               case IDC1_KPAPPLIC:
674                 cfg.app_keypad = IsDlgButtonChecked (hwnd, IDC1_KPAPPLIC);
675                 cfg.nethack_keypad = FALSE;
676                 break;
677               case IDC1_KPNH:
678                 cfg.app_keypad = FALSE;
679                 cfg.nethack_keypad = TRUE;
680                 break;
681               case IDC1_CURNORMAL:
682               case IDC1_CURAPPLIC:
683                 cfg.app_cursor = IsDlgButtonChecked (hwnd, IDC1_CURAPPLIC);
684                 break;
685               case IDC1_ALTF4:
686                 if (HIWORD(wParam) == BN_CLICKED ||
687                     HIWORD(wParam) == BN_DOUBLECLICKED)
688                     cfg.alt_f4 = IsDlgButtonChecked (hwnd, IDC1_ALTF4);
689                 break;
690               case IDC1_ALTSPACE:
691                 if (HIWORD(wParam) == BN_CLICKED ||
692                     HIWORD(wParam) == BN_DOUBLECLICKED)
693                     cfg.alt_space = IsDlgButtonChecked (hwnd, IDC1_ALTSPACE);
694                 break;
695               case IDC1_LDISCTERM:
696                 if (HIWORD(wParam) == BN_CLICKED ||
697                     HIWORD(wParam) == BN_DOUBLECLICKED)
698                     cfg.ldisc_term = IsDlgButtonChecked (hwnd, IDC1_LDISCTERM);
699                 break;
700               case IDC1_SCROLLKEY:
701                 if (HIWORD(wParam) == BN_CLICKED ||
702                     HIWORD(wParam) == BN_DOUBLECLICKED)
703                     cfg.scroll_on_key = IsDlgButtonChecked (hwnd, IDC1_SCROLLKEY);
704                 break;
705             }
706     }
707     return GeneralPanelProc (hwnd, msg, wParam, lParam);
708 }
709
710 static void fmtfont (char *buf) {
711     sprintf (buf, "Font: %s, ", cfg.font);
712     if (cfg.fontisbold)
713         strcat(buf, "bold, ");
714     if (cfg.fontheight == 0)
715         strcat (buf, "default height");
716     else
717         sprintf (buf+strlen(buf), "%d-%s",
718                  (cfg.fontheight < 0 ? -cfg.fontheight : cfg.fontheight),
719                  (cfg.fontheight < 0 ? "pixel" : "point"));
720 }
721
722 static int CALLBACK TerminalProc (HWND hwnd, UINT msg,
723                                     WPARAM wParam, LPARAM lParam) {
724     CHOOSEFONT cf;
725     LOGFONT lf;
726     char fontstatic[256];
727
728     switch (msg) {
729       case WM_INITDIALOG:
730         CheckDlgButton (hwnd, IDC2_WRAPMODE, cfg.wrap_mode);
731         CheckDlgButton (hwnd, IDC2_WINNAME, cfg.win_name_always);
732         CheckDlgButton (hwnd, IDC2_DECOM, cfg.dec_om);
733         CheckDlgButton (hwnd, IDC2_LFHASCR, cfg.lfhascr);
734         SetDlgItemInt (hwnd, IDC2_ROWSEDIT, cfg.height, FALSE);
735         SetDlgItemInt (hwnd, IDC2_COLSEDIT, cfg.width, FALSE);
736         SetDlgItemInt (hwnd, IDC2_SAVEEDIT, cfg.savelines, FALSE);
737         fmtfont (fontstatic);
738         SetDlgItemText (hwnd, IDC2_FONTSTATIC, fontstatic);
739         CheckDlgButton (hwnd, IDC1_BLINKCUR, cfg.blink_cur);
740         CheckDlgButton (hwnd, IDC1_BEEP, cfg.beep);
741         CheckDlgButton (hwnd, IDC2_SCROLLBAR, cfg.scrollbar);
742         CheckDlgButton (hwnd, IDC2_LOCKSIZE, cfg.locksize);
743         CheckDlgButton (hwnd, IDC2_BCE, cfg.bce);
744         CheckDlgButton (hwnd, IDC2_BLINKTEXT, cfg.blinktext);
745         break;
746       case WM_COMMAND:
747         switch (LOWORD(wParam)) {
748           case IDC2_WRAPMODE:
749             if (HIWORD(wParam) == BN_CLICKED ||
750                 HIWORD(wParam) == BN_DOUBLECLICKED)
751                 cfg.wrap_mode = IsDlgButtonChecked (hwnd, IDC2_WRAPMODE);
752             break;
753           case IDC2_WINNAME:
754             if (HIWORD(wParam) == BN_CLICKED ||
755                 HIWORD(wParam) == BN_DOUBLECLICKED)
756                 cfg.win_name_always = IsDlgButtonChecked (hwnd, IDC2_WINNAME);
757             break;
758           case IDC2_DECOM:
759             if (HIWORD(wParam) == BN_CLICKED ||
760                 HIWORD(wParam) == BN_DOUBLECLICKED)
761                 cfg.dec_om = IsDlgButtonChecked (hwnd, IDC2_DECOM);
762             break;
763           case IDC2_LFHASCR:
764             if (HIWORD(wParam) == BN_CLICKED ||
765                 HIWORD(wParam) == BN_DOUBLECLICKED)
766                 cfg.lfhascr = IsDlgButtonChecked (hwnd, IDC2_LFHASCR);
767             break;
768           case IDC2_ROWSEDIT:
769             if (HIWORD(wParam) == EN_CHANGE)
770                 MyGetDlgItemInt (hwnd, IDC2_ROWSEDIT, &cfg.height);
771             break;
772           case IDC2_COLSEDIT:
773             if (HIWORD(wParam) == EN_CHANGE)
774                 MyGetDlgItemInt (hwnd, IDC2_COLSEDIT, &cfg.width);
775             break;
776           case IDC2_SAVEEDIT:
777             if (HIWORD(wParam) == EN_CHANGE)
778                 MyGetDlgItemInt (hwnd, IDC2_SAVEEDIT, &cfg.savelines);
779             break;
780           case IDC2_CHOOSEFONT:
781             lf.lfHeight = cfg.fontheight;
782             lf.lfWidth = lf.lfEscapement = lf.lfOrientation = 0;
783             lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = 0;
784             lf.lfWeight = (cfg.fontisbold ? FW_BOLD : 0);
785             lf.lfCharSet = cfg.fontcharset;
786             lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
787             lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
788             lf.lfQuality = DEFAULT_QUALITY;
789             lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
790             strncpy (lf.lfFaceName, cfg.font, sizeof(lf.lfFaceName)-1);
791             lf.lfFaceName[sizeof(lf.lfFaceName)-1] = '\0';
792
793             cf.lStructSize = sizeof(cf);
794             cf.hwndOwner = hwnd;
795             cf.lpLogFont = &lf;
796             cf.Flags = CF_FIXEDPITCHONLY | CF_FORCEFONTEXIST |
797                 CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
798
799             if (ChooseFont (&cf)) {
800                 strncpy (cfg.font, lf.lfFaceName, sizeof(cfg.font)-1);
801                 cfg.font[sizeof(cfg.font)-1] = '\0';
802                 cfg.fontisbold = (lf.lfWeight == FW_BOLD);
803                 cfg.fontcharset = lf.lfCharSet;
804                 cfg.fontheight = lf.lfHeight;
805                 fmtfont (fontstatic);
806                 SetDlgItemText (hwnd, IDC2_FONTSTATIC, fontstatic);
807             }
808             break;
809            case IDC1_BLINKCUR:
810              if (HIWORD(wParam) == BN_CLICKED ||
811                  HIWORD(wParam) == BN_DOUBLECLICKED)
812                  cfg.blink_cur = IsDlgButtonChecked (hwnd, IDC1_BLINKCUR);
813              break;
814            case IDC1_BEEP:
815              if (HIWORD(wParam) == BN_CLICKED ||
816                  HIWORD(wParam) == BN_DOUBLECLICKED)
817                  cfg.beep = IsDlgButtonChecked (hwnd, IDC1_BEEP);
818              break;
819            case IDC2_SCROLLBAR:
820              if (HIWORD(wParam) == BN_CLICKED ||
821                  HIWORD(wParam) == BN_DOUBLECLICKED)
822                  cfg.scrollbar = IsDlgButtonChecked (hwnd, IDC2_SCROLLBAR);
823              break;
824            case IDC2_LOCKSIZE:
825              if (HIWORD(wParam) == BN_CLICKED ||
826                  HIWORD(wParam) == BN_DOUBLECLICKED)
827                  cfg.locksize = IsDlgButtonChecked (hwnd, IDC2_LOCKSIZE);
828              break;
829            case IDC2_BLINKTEXT:
830              if (HIWORD(wParam) == BN_CLICKED ||
831                  HIWORD(wParam) == BN_DOUBLECLICKED)
832                  cfg.blinktext = IsDlgButtonChecked (hwnd, IDC2_BLINKTEXT);
833              break;
834            case IDC2_BCE:
835              if (HIWORD(wParam) == BN_CLICKED ||
836                  HIWORD(wParam) == BN_DOUBLECLICKED)
837                  cfg.bce = IsDlgButtonChecked (hwnd, IDC2_BCE);
838              break;
839         }
840         break;
841     }
842     return GeneralPanelProc (hwnd, msg, wParam, lParam);
843 }
844
845 static int CALLBACK TelnetProc (HWND hwnd, UINT msg,
846                                     WPARAM wParam, LPARAM lParam) {
847     int i;
848
849     switch (msg) {
850       case WM_INITDIALOG:
851         SetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype);
852         SetDlgItemText (hwnd, IDC3_TSEDIT, cfg.termspeed);
853         SetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username);
854         {
855           char *p = cfg.environmt;
856             while (*p) {
857                 SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_ADDSTRING, 0,
858                                     (LPARAM) p);
859                 p += strlen(p)+1;
860             }
861         }
862         CheckRadioButton (hwnd, IDC3_EMBSD, IDC3_EMRFC,
863                           cfg.rfc_environ ? IDC3_EMRFC : IDC3_EMBSD);
864         break;
865       case WM_COMMAND:
866         switch (LOWORD(wParam)) {
867           case IDC3_TTEDIT:
868             if (HIWORD(wParam) == EN_CHANGE)
869             GetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype,
870                             sizeof(cfg.termtype)-1);
871             break;
872           case IDC3_TSEDIT:
873             if (HIWORD(wParam) == EN_CHANGE)
874                 GetDlgItemText (hwnd, IDC3_TSEDIT, cfg.termspeed,
875                                 sizeof(cfg.termspeed)-1);
876             break;
877           case IDC3_LOGEDIT:
878             if (HIWORD(wParam) == EN_CHANGE)
879                 GetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username,
880                                 sizeof(cfg.username)-1);
881             break;
882           case IDC3_EMBSD:
883           case IDC3_EMRFC:
884             cfg.rfc_environ = IsDlgButtonChecked (hwnd, IDC3_EMRFC);
885             break;
886           case IDC3_ENVADD:
887             if (HIWORD(wParam) == BN_CLICKED ||
888                 HIWORD(wParam) == BN_DOUBLECLICKED) {
889               char str[sizeof(cfg.environmt)];
890                 char *p;
891                 GetDlgItemText (hwnd, IDC3_VAREDIT, str, sizeof(str)-1);
892                 if (!*str) {
893                     MessageBeep(0);
894                     break;
895                 }
896                 p = str + strlen(str);
897                 *p++ = '\t';
898                 GetDlgItemText (hwnd, IDC3_VALEDIT, p, sizeof(str)-1-(p-str));
899                 if (!*p) {
900                     MessageBeep(0);
901                     break;
902                 }
903               p = cfg.environmt;
904                 while (*p) {
905                     while (*p) p++;
906                     p++;
907                 }
908               if ((p-cfg.environmt) + strlen(str) + 2 < sizeof(cfg.environmt)) {
909                     strcpy (p, str);
910                     p[strlen(str)+1] = '\0';
911                     SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_ADDSTRING,
912                                         0, (LPARAM)str);
913                     SetDlgItemText (hwnd, IDC3_VAREDIT, "");
914                     SetDlgItemText (hwnd, IDC3_VALEDIT, "");
915                 } else {
916                     MessageBox(hwnd, "Environment too big", "PuTTY Error",
917                                MB_OK | MB_ICONERROR);
918                 }
919             }
920             break;
921           case IDC3_ENVREMOVE:
922             if (HIWORD(wParam) != BN_CLICKED &&
923                 HIWORD(wParam) != BN_DOUBLECLICKED)
924                 break;
925             i = SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_GETCURSEL, 0, 0);
926             if (i == LB_ERR)
927                 MessageBeep (0);
928             else {
929                 char *p, *q;
930
931                 SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_DELETESTRING,
932                                     i, 0);
933               p = cfg.environmt;
934                 while (i > 0) {
935                     if (!*p)
936                         goto disaster;
937                     while (*p) p++;
938                     p++;
939                     i--;
940                 }
941                 q = p;
942                 if (!*p)
943                     goto disaster;
944                 while (*p) p++;
945                 p++;
946                 while (*p) {
947                     while (*p)
948                         *q++ = *p++;
949                     *q++ = *p++;
950                 }
951                 *q = '\0';
952                 disaster:;
953             }
954             break;
955         }
956         break;
957     }
958     return GeneralPanelProc (hwnd, msg, wParam, lParam);
959 }
960
961 static int CALLBACK SshProc (HWND hwnd, UINT msg,
962                              WPARAM wParam, LPARAM lParam) {
963     OPENFILENAME of;
964     char filename[sizeof(cfg.keyfile)];
965
966     switch (msg) {
967       case WM_INITDIALOG:
968         SetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype);
969         SetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username);
970         CheckDlgButton (hwnd, IDC3_NOPTY, cfg.nopty);
971         CheckDlgButton (hwnd, IDC3_AGENTFWD, cfg.agentfwd);
972         CheckRadioButton (hwnd, IDC3_CIPHER3DES, IDC3_CIPHERDES,
973                           cfg.cipher == CIPHER_BLOWFISH ? IDC3_CIPHERBLOWF :
974                           cfg.cipher == CIPHER_DES ? IDC3_CIPHERDES :
975                           IDC3_CIPHER3DES);
976         CheckRadioButton (hwnd, IDC3_SSHPROT1, IDC3_SSHPROT2,
977                           cfg.sshprot == 1 ? IDC3_SSHPROT1 : IDC3_SSHPROT2);
978         CheckDlgButton (hwnd, IDC3_AUTHTIS, cfg.try_tis_auth);
979         SetDlgItemText (hwnd, IDC3_PKEDIT, cfg.keyfile);
980         break;
981       case WM_COMMAND:
982         switch (LOWORD(wParam)) {
983           case IDC3_TTEDIT:
984             if (HIWORD(wParam) == EN_CHANGE)
985             GetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype,
986                             sizeof(cfg.termtype)-1);
987             break;
988           case IDC3_LOGEDIT:
989             if (HIWORD(wParam) == EN_CHANGE)
990                 GetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username,
991                                 sizeof(cfg.username)-1);
992             break;
993           case IDC3_NOPTY:
994             if (HIWORD(wParam) == BN_CLICKED ||
995                 HIWORD(wParam) == BN_DOUBLECLICKED)
996                 cfg.nopty = IsDlgButtonChecked (hwnd, IDC3_NOPTY);
997             break;
998           case IDC3_AGENTFWD:
999             if (HIWORD(wParam) == BN_CLICKED ||
1000                 HIWORD(wParam) == BN_DOUBLECLICKED)
1001                 cfg.agentfwd = IsDlgButtonChecked (hwnd, IDC3_AGENTFWD);
1002             break;
1003           case IDC3_CIPHER3DES:
1004           case IDC3_CIPHERBLOWF:
1005           case IDC3_CIPHERDES:
1006             if (HIWORD(wParam) == BN_CLICKED ||
1007                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1008                 if (IsDlgButtonChecked (hwnd, IDC3_CIPHER3DES))
1009                     cfg.cipher = CIPHER_3DES;
1010                 else if (IsDlgButtonChecked (hwnd, IDC3_CIPHERBLOWF))
1011                     cfg.cipher = CIPHER_BLOWFISH;
1012                 else if (IsDlgButtonChecked (hwnd, IDC3_CIPHERDES))
1013                     cfg.cipher = CIPHER_DES;
1014             }
1015             break;
1016           case IDC3_SSHPROT1:
1017           case IDC3_SSHPROT2:
1018             if (HIWORD(wParam) == BN_CLICKED ||
1019                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1020                 if (IsDlgButtonChecked (hwnd, IDC3_SSHPROT1))
1021                     cfg.sshprot = 1;
1022                 else if (IsDlgButtonChecked (hwnd, IDC3_SSHPROT2))
1023                     cfg.sshprot = 2;
1024             }
1025             break;
1026           case IDC3_AUTHTIS:
1027             if (HIWORD(wParam) == BN_CLICKED ||
1028                 HIWORD(wParam) == BN_DOUBLECLICKED)
1029                 cfg.try_tis_auth = IsDlgButtonChecked (hwnd, IDC3_AUTHTIS);
1030             break;
1031           case IDC3_PKEDIT:
1032             if (HIWORD(wParam) == EN_CHANGE)
1033                 GetDlgItemText (hwnd, IDC3_PKEDIT, cfg.keyfile,
1034                                 sizeof(cfg.keyfile)-1);
1035             break;
1036           case IDC3_PKBUTTON:
1037             /*
1038              * FIXME: this crashes. Find out why.
1039              */
1040             memset(&of, 0, sizeof(of));
1041 #ifdef OPENFILENAME_SIZE_VERSION_400
1042             of.lStructSize = OPENFILENAME_SIZE_VERSION_400;
1043 #else
1044             of.lStructSize = sizeof(of);
1045 #endif
1046             of.hwndOwner = hwnd;
1047             of.lpstrFilter = "All Files\0*\0\0\0";
1048             of.lpstrCustomFilter = NULL;
1049             of.nFilterIndex = 1;
1050             of.lpstrFile = filename; strcpy(filename, cfg.keyfile);
1051             of.nMaxFile = sizeof(filename);
1052             of.lpstrFileTitle = NULL;
1053             of.lpstrInitialDir = NULL;
1054             of.lpstrTitle = "Select Public Key File";
1055             of.Flags = 0;
1056             if (GetOpenFileName(&of)) {
1057                 strcpy(cfg.keyfile, filename);
1058                 SetDlgItemText (hwnd, IDC3_PKEDIT, cfg.keyfile);
1059             }
1060             break;
1061         }
1062         break;
1063     }
1064     return GeneralPanelProc (hwnd, msg, wParam, lParam);
1065 }
1066
1067 static int CALLBACK SelectionProc (HWND hwnd, UINT msg,
1068                                     WPARAM wParam, LPARAM lParam) {
1069     int i;
1070
1071     switch (msg) {
1072       case WM_INITDIALOG:
1073         CheckRadioButton (hwnd, IDC4_MBWINDOWS, IDC4_MBXTERM,
1074                           cfg.mouse_is_xterm ? IDC4_MBXTERM : IDC4_MBWINDOWS);
1075         {
1076             static int tabs[4] = {25, 61, 96, 128};
1077             SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_SETTABSTOPS, 4,
1078                                 (LPARAM) tabs);
1079         }
1080         for (i=0; i<256; i++) {
1081             char str[100];
1082             sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
1083                     (i>=0x21 && i != 0x7F) ? i : ' ',
1084                     cfg.wordness[i]);
1085             SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_ADDSTRING, 0,
1086                                 (LPARAM) str);
1087         }
1088         break;
1089       case WM_COMMAND:
1090         switch (LOWORD(wParam)) {
1091           case IDC4_MBWINDOWS:
1092           case IDC4_MBXTERM:
1093             cfg.mouse_is_xterm = IsDlgButtonChecked (hwnd, IDC4_MBXTERM);
1094             break;
1095           case IDC4_CCSET:
1096             {
1097                 BOOL ok;
1098                 int i;
1099                 int n = GetDlgItemInt (hwnd, IDC4_CCEDIT, &ok, FALSE);
1100
1101                 if (!ok)
1102                     MessageBeep (0);
1103                 else {
1104                     for (i=0; i<256; i++)
1105                         if (SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_GETSEL,
1106                                                 i, 0)) {
1107                             char str[100];
1108                             cfg.wordness[i] = n;
1109                             SendDlgItemMessage (hwnd, IDC4_CCLIST,
1110                                                 LB_DELETESTRING, i, 0);
1111                             sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
1112                                     (i>=0x21 && i != 0x7F) ? i : ' ',
1113                                     cfg.wordness[i]);
1114                             SendDlgItemMessage (hwnd, IDC4_CCLIST,
1115                                                 LB_INSERTSTRING, i,
1116                                                 (LPARAM)str);
1117                         }
1118                 }
1119             }
1120             break;
1121         }
1122         break;
1123     }
1124     return GeneralPanelProc (hwnd, msg, wParam, lParam);
1125 }
1126
1127 static int CALLBACK ColourProc (HWND hwnd, UINT msg,
1128                                     WPARAM wParam, LPARAM lParam) {
1129     static const char *const colours[] = {
1130         "Default Foreground", "Default Bold Foreground",
1131         "Default Background", "Default Bold Background",
1132         "Cursor Text", "Cursor Colour",
1133         "ANSI Black", "ANSI Black Bold",
1134         "ANSI Red", "ANSI Red Bold",
1135         "ANSI Green", "ANSI Green Bold",
1136         "ANSI Yellow", "ANSI Yellow Bold",
1137         "ANSI Blue", "ANSI Blue Bold",
1138         "ANSI Magenta", "ANSI Magenta Bold",
1139         "ANSI Cyan", "ANSI Cyan Bold",
1140         "ANSI White", "ANSI White Bold"
1141     };
1142     static const int permanent[] = {
1143         TRUE, FALSE, TRUE, FALSE, TRUE, TRUE,
1144         TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE,
1145         TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE
1146     };
1147     switch (msg) {
1148       case WM_INITDIALOG:
1149         CheckDlgButton (hwnd, IDC5_BOLDCOLOUR, cfg.bold_colour);
1150         CheckDlgButton (hwnd, IDC5_PALETTE, cfg.try_palette);
1151         {
1152             int i;
1153             for (i=0; i<22; i++)
1154                 if (cfg.bold_colour || permanent[i])
1155                     SendDlgItemMessage (hwnd, IDC5_LIST, LB_ADDSTRING, 0,
1156                                         (LPARAM) colours[i]);
1157         }
1158         SendDlgItemMessage (hwnd, IDC5_LIST, LB_SETCURSEL, 0, 0);
1159         SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[0][0], FALSE);
1160         SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[0][1], FALSE);
1161         SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[0][2], FALSE);
1162         break;
1163       case WM_COMMAND:
1164         switch (LOWORD(wParam)) {
1165           case IDC5_BOLDCOLOUR:
1166             if (HIWORD(wParam) == BN_CLICKED ||
1167                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1168                 int n, i;
1169                 cfg.bold_colour = IsDlgButtonChecked (hwnd, IDC5_BOLDCOLOUR);
1170                 n = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCOUNT, 0, 0);
1171                 if (cfg.bold_colour && n!=22) {
1172                     for (i=0; i<22; i++)
1173                         if (!permanent[i])
1174                             SendDlgItemMessage (hwnd, IDC5_LIST,
1175                                                 LB_INSERTSTRING, i,
1176                                                 (LPARAM) colours[i]);
1177                 } else if (!cfg.bold_colour && n!=12) {
1178                     for (i=22; i-- ;)
1179                         if (!permanent[i])
1180                             SendDlgItemMessage (hwnd, IDC5_LIST,
1181                                                 LB_DELETESTRING, i, 0);
1182                 }
1183             }
1184             break;
1185           case IDC5_PALETTE:
1186             if (HIWORD(wParam) == BN_CLICKED ||
1187                 HIWORD(wParam) == BN_DOUBLECLICKED)
1188                 cfg.try_palette = IsDlgButtonChecked (hwnd, IDC5_PALETTE);
1189             break;
1190           case IDC5_LIST:
1191             if (HIWORD(wParam) == LBN_DBLCLK ||
1192                 HIWORD(wParam) == LBN_SELCHANGE) {
1193                 int i = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCURSEL,
1194                                             0, 0);
1195                 if (!cfg.bold_colour)
1196                     i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
1197                 SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[i][0], FALSE);
1198                 SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[i][1], FALSE);
1199                 SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[i][2], FALSE);
1200             }
1201             break;
1202           case IDC5_CHANGE:
1203             if (HIWORD(wParam) == BN_CLICKED ||
1204                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1205                 static CHOOSECOLOR cc;
1206                 static DWORD custom[16] = {0};   /* zero initialisers */
1207                 int i = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCURSEL,
1208                                             0, 0);
1209                 if (!cfg.bold_colour)
1210                     i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
1211                 cc.lStructSize = sizeof(cc);
1212                 cc.hwndOwner = hwnd;
1213                 cc.hInstance = (HWND)hinst;
1214                 cc.lpCustColors = custom;
1215                 cc.rgbResult = RGB (cfg.colours[i][0], cfg.colours[i][1],
1216                                     cfg.colours[i][2]);
1217                 cc.Flags = CC_FULLOPEN | CC_RGBINIT;
1218                 if (ChooseColor(&cc)) {
1219                     cfg.colours[i][0] =
1220                         (unsigned char) (cc.rgbResult & 0xFF);
1221                     cfg.colours[i][1] =
1222                         (unsigned char) (cc.rgbResult >> 8) & 0xFF;
1223                     cfg.colours[i][2] =
1224                         (unsigned char) (cc.rgbResult >> 16) & 0xFF;
1225                     SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[i][0],
1226                                    FALSE);
1227                     SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[i][1],
1228                                    FALSE);
1229                     SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[i][2],
1230                                    FALSE);
1231                 }
1232             }
1233             break;
1234         }
1235         break;
1236     }
1237     return GeneralPanelProc (hwnd, msg, wParam, lParam);
1238 }
1239
1240 static int CALLBACK TranslationProc (HWND hwnd, UINT msg,
1241                                   WPARAM wParam, LPARAM lParam) {
1242     switch (msg) {
1243       case WM_INITDIALOG:
1244         CheckRadioButton (hwnd, IDC6_NOXLAT, IDC6_88592WIN1250,
1245                           cfg.xlat_88592w1250 ? IDC6_88592WIN1250 :
1246                           cfg.xlat_enablekoiwin ? IDC6_KOI8WIN1251 :
1247                           IDC6_NOXLAT);
1248         CheckDlgButton (hwnd, IDC6_CAPSLOCKCYR, cfg.xlat_capslockcyr);
1249         CheckRadioButton (hwnd, IDC2_VTXWINDOWS, IDC2_VTPOORMAN,
1250                           cfg.vtmode == VT_XWINDOWS ? IDC2_VTXWINDOWS :
1251                           cfg.vtmode == VT_OEMANSI ? IDC2_VTOEMANSI :
1252                           cfg.vtmode == VT_OEMONLY ? IDC2_VTOEMONLY :
1253                           IDC2_VTPOORMAN);
1254       case WM_COMMAND:
1255         switch (LOWORD(wParam)) {
1256           case IDC6_NOXLAT:
1257           case IDC6_KOI8WIN1251:
1258           case IDC6_88592WIN1250:
1259             cfg.xlat_enablekoiwin =
1260                 IsDlgButtonChecked (hwnd, IDC6_KOI8WIN1251);
1261             cfg.xlat_88592w1250 =
1262                 IsDlgButtonChecked (hwnd, IDC6_88592WIN1250);
1263             break;
1264           case IDC6_CAPSLOCKCYR:
1265             if (HIWORD(wParam) == BN_CLICKED ||
1266                 HIWORD(wParam) == BN_DOUBLECLICKED) {
1267                 cfg.xlat_capslockcyr =
1268                     IsDlgButtonChecked (hwnd, IDC6_CAPSLOCKCYR);
1269             }
1270             break;
1271           case IDC2_VTXWINDOWS:
1272           case IDC2_VTOEMANSI:
1273           case IDC2_VTOEMONLY:
1274           case IDC2_VTPOORMAN:
1275             cfg.vtmode =
1276                 (IsDlgButtonChecked (hwnd, IDC2_VTXWINDOWS) ? VT_XWINDOWS :
1277                  IsDlgButtonChecked (hwnd, IDC2_VTOEMANSI) ? VT_OEMANSI :
1278                  IsDlgButtonChecked (hwnd, IDC2_VTOEMONLY) ? VT_OEMONLY :
1279                  VT_POORMAN);
1280             break;
1281         }
1282     }
1283     return GeneralPanelProc (hwnd, msg, wParam, lParam);
1284 }
1285
1286 static DLGPROC panelproc[NPANELS] = {
1287     ConnectionProc, KeyboardProc, TerminalProc,
1288     TelnetProc, SshProc, SelectionProc, ColourProc, TranslationProc
1289 };
1290 static char *panelids[NPANELS] = {
1291     MAKEINTRESOURCE(IDD_PANEL0),
1292     MAKEINTRESOURCE(IDD_PANEL1),
1293     MAKEINTRESOURCE(IDD_PANEL2),
1294     MAKEINTRESOURCE(IDD_PANEL3),
1295     MAKEINTRESOURCE(IDD_PANEL35),
1296     MAKEINTRESOURCE(IDD_PANEL4),
1297     MAKEINTRESOURCE(IDD_PANEL5),
1298     MAKEINTRESOURCE(IDD_PANEL6)
1299 };
1300
1301 static char *names[NPANELS] = {
1302     "Connection", "Keyboard", "Terminal", "Telnet",
1303     "SSH", "Selection", "Colours", "Translation"
1304 };
1305
1306 static int mainp[MAIN_NPANELS] = { 0, 1, 2, 3, 4, 5, 6, 7};
1307 static int reconfp[RECONF_NPANELS] = { 1, 2, 5, 6, 7};
1308
1309 static int GenericMainDlgProc (HWND hwnd, UINT msg,
1310                                WPARAM wParam, LPARAM lParam,
1311                                int npanels, int *panelnums, HWND *page) {
1312     HWND hw;
1313
1314     switch (msg) {
1315       case WM_INITDIALOG:
1316         {                              /* centre the window */
1317             RECT rs, rd;
1318
1319             hw = GetDesktopWindow();
1320             if (GetWindowRect (hw, &rs) && GetWindowRect (hwnd, &rd))
1321                 MoveWindow (hwnd, (rs.right + rs.left + rd.left - rd.right)/2,
1322                             (rs.bottom + rs.top + rd.top - rd.bottom)/2,
1323                             rd.right-rd.left, rd.bottom-rd.top, TRUE);
1324         }
1325         *page = NULL;
1326         {                              /* initialise the tab control */
1327             TC_ITEMHEADER tab;
1328             int i;
1329
1330             hw = GetDlgItem (hwnd, IDC_TAB);
1331             for (i=0; i<npanels; i++) {
1332                 tab.mask = TCIF_TEXT;
1333                 tab.pszText = names[panelnums[i]];
1334                 TabCtrl_InsertItem (hw, i, &tab);
1335             }
1336 /*          *page = CreateDialogIndirect (hinst, panels[panelnums[0]].temp,
1337                                           hwnd, panelproc[panelnums[0]]);*/
1338             *page = CreateDialog (hinst, panelids[panelnums[0]],
1339                                   hwnd, panelproc[panelnums[0]]);
1340             SetWindowLong (*page, GWL_EXSTYLE,
1341                            GetWindowLong (*page, GWL_EXSTYLE) |
1342                            WS_EX_CONTROLPARENT);
1343         }
1344         SetFocus (*page);
1345         return 0;
1346       case WM_NOTIFY:
1347         if (LOWORD(wParam) == IDC_TAB &&
1348             ((LPNMHDR)lParam)->code == TCN_SELCHANGE) {
1349             int i = TabCtrl_GetCurSel(((LPNMHDR)lParam)->hwndFrom);
1350             if (*page)
1351                 DestroyWindow (*page);
1352 /*          *page = CreateDialogIndirect (hinst, panels[panelnums[i]].temp,     
1353                                           hwnd, panelproc[panelnums[i]]);*/
1354             *page = CreateDialog (hinst, panelids[panelnums[i]],
1355                                   hwnd, panelproc[panelnums[i]]);
1356             SetWindowLong (*page, GWL_EXSTYLE,
1357                            GetWindowLong (*page, GWL_EXSTYLE) |
1358                            WS_EX_CONTROLPARENT);
1359             SetFocus (((LPNMHDR)lParam)->hwndFrom);   /* ensure focus stays */
1360             return 0;
1361         }
1362         break;
1363 /*      case WM_CTLCOLORDLG: */
1364 /*      return (int) GetStockObject (LTGRAY_BRUSH); */
1365       case WM_COMMAND:
1366         switch (LOWORD(wParam)) {
1367           case IDOK:
1368             if (*cfg.host)
1369                 EndDialog (hwnd, 1);
1370             else
1371                 MessageBeep (0);
1372             return 0;
1373           case IDCANCEL:
1374             EndDialog (hwnd, 0);
1375             return 0;
1376         }
1377         return 0;
1378       case WM_CLOSE:
1379         EndDialog (hwnd, 0);
1380         return 0;
1381
1382         /* Grrr Explorer will maximize Dialogs! */
1383       case WM_SIZE:
1384         if (wParam == SIZE_MAXIMIZED)
1385            force_normal(hwnd);
1386         return 0;
1387     }
1388     return 0;
1389 }
1390
1391 static int CALLBACK MainDlgProc (HWND hwnd, UINT msg,
1392                                  WPARAM wParam, LPARAM lParam) {
1393 #if 0
1394     HWND hw;
1395     int i;
1396 #endif
1397     static HWND page = NULL;
1398
1399     if (msg == WM_COMMAND && LOWORD(wParam) == IDOK) {
1400 #if 0
1401         /*
1402          * If the Connection panel is active and the Session List
1403          * box is selected, we treat a press of Open to have an
1404          * implicit press of Load preceding it.
1405          */
1406         hw = GetDlgItem (hwnd, IDC_TAB);
1407         i = TabCtrl_GetCurSel(hw);
1408         if (panelproc[mainp[i]] == ConnectionProc &&
1409             page && implicit_load_ok) {
1410             SendMessage (page, WM_COMMAND,
1411                          MAKELONG(IDC0_SESSLOAD, BN_CLICKED), 0);
1412         }
1413 #endif
1414     }
1415     if (msg == WM_COMMAND && LOWORD(wParam) == IDC_ABOUT) {
1416         EnableWindow(hwnd, 0);
1417         DialogBox(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
1418                   GetParent(hwnd), AboutProc);
1419         EnableWindow(hwnd, 1);
1420         SetActiveWindow(hwnd);
1421     }
1422     return GenericMainDlgProc (hwnd, msg, wParam, lParam,
1423                                MAIN_NPANELS, mainp, &page);
1424 }
1425
1426 static int CALLBACK ReconfDlgProc (HWND hwnd, UINT msg,
1427                                    WPARAM wParam, LPARAM lParam) {
1428     static HWND page;
1429     return GenericMainDlgProc (hwnd, msg, wParam, lParam,
1430                                RECONF_NPANELS, reconfp, &page);
1431 }
1432
1433 void get_sesslist(int allocate) {
1434     static char otherbuf[2048];
1435     static char *buffer;
1436     int buflen, bufsize, i;
1437     char *p, *ret;
1438     void *handle;
1439
1440     if (allocate) {
1441         
1442         if ((handle = enum_settings_start()) == NULL)
1443             return;
1444
1445         buflen = bufsize = 0;
1446         buffer = NULL;
1447         do {
1448             ret = enum_settings_next(handle, otherbuf, sizeof(otherbuf));
1449             if (ret) {
1450                 int len = strlen(otherbuf)+1;
1451                 if (bufsize < buflen+len) {
1452                     bufsize = buflen + len + 2048;
1453                     buffer = srealloc(buffer, bufsize);
1454                 }
1455                 strcpy(buffer+buflen, otherbuf);
1456                 buflen += strlen(buffer+buflen)+1;
1457             }
1458         } while (ret);
1459         enum_settings_finish(handle);
1460         buffer = srealloc(buffer, buflen+1);
1461         buffer[buflen] = '\0';
1462
1463         p = buffer;
1464         nsessions = 1;                 /* "Default Settings" counts as one */
1465         while (*p) {
1466             if (strcmp(p, "Default Settings"))
1467                 nsessions++;
1468             while (*p) p++;
1469             p++;
1470         }
1471
1472         sessions = smalloc(nsessions * sizeof(char *));
1473         sessions[0] = "Default Settings";
1474         p = buffer;
1475         i = 1;
1476         while (*p) {
1477             if (strcmp(p, "Default Settings"))
1478                 sessions[i++] = p;
1479             while (*p) p++;
1480             p++;
1481         }
1482     } else {
1483         sfree (buffer);
1484         sfree (sessions);
1485     }
1486 }
1487
1488 int do_config (void) {
1489     int ret;
1490
1491     get_sesslist(TRUE);
1492     savedsession[0] = '\0';
1493     ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_MAINBOX), NULL, MainDlgProc);
1494     get_sesslist(FALSE);
1495
1496     return ret;
1497 }
1498
1499 int do_reconfig (HWND hwnd) {
1500     Config backup_cfg;
1501     int ret;
1502
1503     backup_cfg = cfg;                  /* structure copy */
1504     ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_RECONF), hwnd, ReconfDlgProc);
1505     if (!ret)
1506         cfg = backup_cfg;              /* structure copy */
1507     else
1508         force_normal(hwnd);
1509
1510     return ret;
1511 }
1512
1513 void do_defaults (char *session) {
1514     if (session)
1515         load_settings (session, TRUE);
1516     else
1517         load_settings ("Default Settings", FALSE);
1518 }
1519
1520 void logevent (char *string) {
1521     if (nevents >= negsize) {
1522         negsize += 64;
1523         events = srealloc (events, negsize * sizeof(*events));
1524     }
1525     events[nevents] = smalloc(1+strlen(string));
1526     strcpy (events[nevents], string);
1527     nevents++;
1528     if (logbox) {
1529         int count;
1530         SendDlgItemMessage (logbox, IDN_LIST, LB_ADDSTRING,
1531                             0, (LPARAM)string);
1532         count = SendDlgItemMessage (logbox, IDN_LIST, LB_GETCOUNT, 0, 0);
1533         SendDlgItemMessage (logbox, IDN_LIST, LB_SETTOPINDEX, count-1, 0);
1534     }
1535 }
1536
1537 void showeventlog (HWND hwnd) {
1538     if (!logbox) {
1539         logbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_LOGBOX),
1540                                hwnd, LogProc);
1541         ShowWindow (logbox, SW_SHOWNORMAL);
1542     }
1543 }
1544
1545 void showabout (HWND hwnd) {
1546     if (!abtbox) {
1547         abtbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
1548                                hwnd, AboutProc);
1549         ShowWindow (abtbox, SW_SHOWNORMAL);
1550     }
1551 }
1552
1553 void verify_ssh_host_key(char *host, char *keytype,
1554                          char *keystr, char *fingerprint) {
1555     int ret;
1556
1557     static const char absentmsg[] =
1558         "The server's host key is not cached in the registry. You\n"
1559         "have no guarantee that the server is the computer you\n"
1560         "think it is.\n"
1561         "The server's key fingerprint is:\n"
1562         "%s\n"
1563         "If you trust this host, hit Yes to add the key to\n"
1564         "PuTTY's cache and carry on connecting.\n"
1565         "If you do not trust this host, hit No to abandon the\n"
1566         "connection.\n";
1567
1568     static const char wrongmsg[] =
1569         "WARNING - POTENTIAL SECURITY BREACH!\n"
1570         "\n"
1571         "The server's host key does not match the one PuTTY has\n"
1572         "cached in the registry. This means that either the\n"
1573         "server administrator has changed the host key, or you\n"
1574         "have actually connected to another computer pretending\n"
1575         "to be the server.\n"
1576         "The new key fingerprint is:\n"
1577         "%s\n"
1578         "If you were expecting this change and trust the new key,\n"
1579         "hit Yes to update PuTTY's cache and continue connecting.\n"
1580         "If you want to carry on connecting but without updating\n"
1581         "the cache, hit No.\n"
1582         "If you want to abandon the connection completely, hit\n"
1583         "Cancel. Hitting Cancel is the ONLY guaranteed safe\n"
1584         "choice.\n";
1585
1586     static const char mbtitle[] = "PuTTY Security Alert";
1587
1588     
1589     char message[160+                  /* sensible fingerprint max size */
1590                  (sizeof(absentmsg) > sizeof(wrongmsg) ?
1591                   sizeof(absentmsg) : sizeof(wrongmsg))];
1592
1593     /*
1594      * Verify the key against the registry.
1595      */
1596     ret = verify_host_key(host, keytype, keystr);
1597
1598     if (ret == 0)                      /* success - key matched OK */
1599         return;
1600     if (ret == 2) {                    /* key was different */
1601         int mbret;
1602         sprintf(message, wrongmsg, fingerprint);
1603         mbret = MessageBox(NULL, message, mbtitle,
1604                            MB_ICONWARNING | MB_YESNOCANCEL);
1605         if (mbret == IDYES)
1606             store_host_key(host, keytype, keystr);
1607         if (mbret == IDCANCEL)
1608             exit(0);
1609     }
1610     if (ret == 1) {                    /* key was absent */
1611         int mbret;
1612         sprintf(message, absentmsg, fingerprint);
1613         mbret = MessageBox(NULL, message, mbtitle,
1614                            MB_ICONWARNING | MB_YESNO);
1615         if (mbret == IDNO)
1616             exit(0);
1617         store_host_key(host, keytype, keystr);
1618     }
1619 }