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