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