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