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