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