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