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