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