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