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