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