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