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