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