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