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