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