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