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