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