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