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