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