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