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