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