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