Revamp the auto-layout of PuTTY configuration box controls. They are
[u/mdw/putty] / windlg.c
1 #include <windows.h>
2 #include <commctrl.h>
3 #include <commdlg.h>
4 #ifndef AUTO_WINSOCK
5 #ifdef WINSOCK_TWO
6 #include <winsock2.h>
7 #else
8 #include <winsock.h>
9 #endif
10 #endif
11 #include <stdio.h>
12 #include <stdlib.h>
13
14 #include "ssh.h"
15 #include "putty.h"
16 #include "win_res.h"
17 #include "storage.h"
18
19 #define NPANELS 9
20 #define MAIN_NPANELS 9
21 #define RECONF_NPANELS 6
22
23 static char **events = NULL;
24 static int nevents = 0, negsize = 0;
25
26 static HWND logbox = NULL, abtbox = NULL;
27
28 static void gpps(void *handle, char *name, char *def, char *val, int len) {
29 if (!read_setting_s(handle, name, val, len)) {
30 strncpy(val, def, len);
31 val[len-1] = '\0';
32 }
33 }
34
35 static void gppi(void *handle, char *name, int def, int *i) {
36 *i = read_setting_i(handle, name, def);
37 }
38
39 static HINSTANCE hinst;
40
41 static int readytogo;
42
43 static void save_settings (char *section, int do_host) {
44 int i;
45 char *p;
46 void *sesskey;
47
48 sesskey = open_settings_w(section);
49 if (!sesskey)
50 return;
51
52 write_setting_i (sesskey, "Present", 1);
53 if (do_host) {
54 write_setting_s (sesskey, "HostName", cfg.host);
55 write_setting_i (sesskey, "PortNumber", cfg.port);
56 p = "raw";
57 for (i = 0; backends[i].name != NULL; i++)
58 if (backends[i].protocol == cfg.protocol) {
59 p = backends[i].name;
60 break;
61 }
62 write_setting_s (sesskey, "Protocol", p);
63 }
64 write_setting_i (sesskey, "CloseOnExit", !!cfg.close_on_exit);
65 write_setting_i (sesskey, "WarnOnClose", !!cfg.warn_on_close);
66 write_setting_s (sesskey, "TerminalType", cfg.termtype);
67 write_setting_s (sesskey, "TerminalSpeed", cfg.termspeed);
68 {
69 char buf[2*sizeof(cfg.environmt)], *p, *q;
70 p = buf;
71 q = cfg.environmt;
72 while (*q) {
73 while (*q) {
74 int c = *q++;
75 if (c == '=' || c == ',' || c == '\\')
76 *p++ = '\\';
77 if (c == '\t')
78 c = '=';
79 *p++ = c;
80 }
81 *p++ = ',';
82 q++;
83 }
84 *p = '\0';
85 write_setting_s (sesskey, "Environment", buf);
86 }
87 write_setting_s (sesskey, "UserName", cfg.username);
88 write_setting_i (sesskey, "NoPTY", cfg.nopty);
89 write_setting_i (sesskey, "AgentFwd", cfg.agentfwd);
90 write_setting_s (sesskey, "RemoteCmd", cfg.remote_cmd);
91 write_setting_s (sesskey, "Cipher", cfg.cipher == CIPHER_BLOWFISH ? "blowfish" :
92 cfg.cipher == CIPHER_DES ? "des" : "3des");
93 write_setting_i (sesskey, "AuthTIS", cfg.try_tis_auth);
94 write_setting_i (sesskey, "SshProt", cfg.sshprot);
95 write_setting_s (sesskey, "PublicKeyFile", cfg.keyfile);
96 write_setting_s (sesskey, "RemoteCommand", cfg.remote_cmd);
97 write_setting_i (sesskey, "RFCEnviron", cfg.rfc_environ);
98 write_setting_i (sesskey, "BackspaceIsDelete", cfg.bksp_is_delete);
99 write_setting_i (sesskey, "RXVTHomeEnd", cfg.rxvt_homeend);
100 write_setting_i (sesskey, "LinuxFunctionKeys", cfg.funky_type);
101 write_setting_i (sesskey, "ApplicationCursorKeys", cfg.app_cursor);
102 write_setting_i (sesskey, "ApplicationKeypad", cfg.app_keypad);
103 write_setting_i (sesskey, "NetHackKeypad", cfg.nethack_keypad);
104 write_setting_i (sesskey, "AltF4", cfg.alt_f4);
105 write_setting_i (sesskey, "AltSpace", cfg.alt_space);
106 write_setting_i (sesskey, "LdiscTerm", cfg.ldisc_term);
107 write_setting_i (sesskey, "BlinkCur", cfg.blink_cur);
108 write_setting_i (sesskey, "Beep", cfg.beep);
109 write_setting_i (sesskey, "ScrollbackLines", cfg.savelines);
110 write_setting_i (sesskey, "DECOriginMode", cfg.dec_om);
111 write_setting_i (sesskey, "AutoWrapMode", cfg.wrap_mode);
112 write_setting_i (sesskey, "LFImpliesCR", cfg.lfhascr);
113 write_setting_i (sesskey, "WinNameAlways", cfg.win_name_always);
114 write_setting_s (sesskey, "WinTitle", cfg.wintitle);
115 write_setting_i (sesskey, "TermWidth", cfg.width);
116 write_setting_i (sesskey, "TermHeight", cfg.height);
117 write_setting_s (sesskey, "Font", cfg.font);
118 write_setting_i (sesskey, "FontIsBold", cfg.fontisbold);
119 write_setting_i (sesskey, "FontCharSet", cfg.fontcharset);
120 write_setting_i (sesskey, "FontHeight", cfg.fontheight);
121 write_setting_i (sesskey, "FontVTMode", cfg.vtmode);
122 write_setting_i (sesskey, "TryPalette", cfg.try_palette);
123 write_setting_i (sesskey, "BoldAsColour", cfg.bold_colour);
124 for (i=0; i<22; i++) {
125 char buf[20], buf2[30];
126 sprintf(buf, "Colour%d", i);
127 sprintf(buf2, "%d,%d,%d", cfg.colours[i][0],
128 cfg.colours[i][1], cfg.colours[i][2]);
129 write_setting_s (sesskey, buf, buf2);
130 }
131 write_setting_i (sesskey, "MouseIsXterm", cfg.mouse_is_xterm);
132 for (i=0; i<256; i+=32) {
133 char buf[20], buf2[256];
134 int j;
135 sprintf(buf, "Wordness%d", i);
136 *buf2 = '\0';
137 for (j=i; j<i+32; j++) {
138 sprintf(buf2+strlen(buf2), "%s%d",
139 (*buf2 ? "," : ""), cfg.wordness[j]);
140 }
141 write_setting_s (sesskey, buf, buf2);
142 }
143 write_setting_i (sesskey, "KoiWinXlat", cfg.xlat_enablekoiwin);
144 write_setting_i (sesskey, "88592Xlat", cfg.xlat_88592w1250);
145 write_setting_i (sesskey, "CapsLockCyr", cfg.xlat_capslockcyr);
146 write_setting_i (sesskey, "ScrollBar", cfg.scrollbar);
147 write_setting_i (sesskey, "ScrollOnKey", cfg.scroll_on_key);
148 write_setting_i (sesskey, "LockSize", cfg.locksize);
149 write_setting_i (sesskey, "BCE", cfg.bce);
150 write_setting_i (sesskey, "BlinkText", cfg.blinktext);
151
152 close_settings_w(sesskey);
153 }
154
155 static void load_settings (char *section, int do_host) {
156 int i;
157 char prot[10];
158 void *sesskey;
159
160 sesskey = open_settings_r(section);
161
162 gpps (sesskey, "HostName", "", cfg.host, sizeof(cfg.host));
163 gppi (sesskey, "PortNumber", default_port, &cfg.port);
164
165 gpps (sesskey, "Protocol", "default", prot, 10);
166 cfg.protocol = default_protocol;
167 for (i = 0; backends[i].name != NULL; i++)
168 if (!strcmp(prot, backends[i].name)) {
169 cfg.protocol = backends[i].protocol;
170 break;
171 }
172
173 gppi (sesskey, "CloseOnExit", 1, &cfg.close_on_exit);
174 gppi (sesskey, "WarnOnClose", 1, &cfg.warn_on_close);
175 gpps (sesskey, "TerminalType", "xterm", cfg.termtype,
176 sizeof(cfg.termtype));
177 gpps (sesskey, "TerminalSpeed", "38400,38400", cfg.termspeed,
178 sizeof(cfg.termspeed));
179 {
180 char buf[2*sizeof(cfg.environmt)], *p, *q;
181 gpps (sesskey, "Environment", "", buf, sizeof(buf));
182 p = buf;
183 q = cfg.environmt;
184 while (*p) {
185 while (*p && *p != ',') {
186 int c = *p++;
187 if (c == '=')
188 c = '\t';
189 if (c == '\\')
190 c = *p++;
191 *q++ = c;
192 }
193 if (*p == ',') p++;
194 *q++ = '\0';
195 }
196 *q = '\0';
197 }
198 gpps (sesskey, "UserName", "", cfg.username, sizeof(cfg.username));
199 gppi (sesskey, "NoPTY", 0, &cfg.nopty);
200 gppi (sesskey, "AgentFwd", 0, &cfg.agentfwd);
201 gpps (sesskey, "RemoteCmd", "", cfg.remote_cmd, sizeof(cfg.remote_cmd));
202 {
203 char cipher[10];
204 gpps (sesskey, "Cipher", "3des", cipher, 10);
205 if (!strcmp(cipher, "blowfish"))
206 cfg.cipher = CIPHER_BLOWFISH;
207 else if (!strcmp(cipher, "des"))
208 cfg.cipher = CIPHER_DES;
209 else
210 cfg.cipher = CIPHER_3DES;
211 }
212 gppi (sesskey, "SshProt", 1, &cfg.sshprot);
213 gppi (sesskey, "AuthTIS", 0, &cfg.try_tis_auth);
214 gpps (sesskey, "PublicKeyFile", "", cfg.keyfile, sizeof(cfg.keyfile));
215 gpps (sesskey, "RemoteCommand", "", cfg.remote_cmd,
216 sizeof(cfg.remote_cmd));
217 gppi (sesskey, "RFCEnviron", 0, &cfg.rfc_environ);
218 gppi (sesskey, "BackspaceIsDelete", 1, &cfg.bksp_is_delete);
219 gppi (sesskey, "RXVTHomeEnd", 0, &cfg.rxvt_homeend);
220 gppi (sesskey, "LinuxFunctionKeys", 0, &cfg.funky_type);
221 gppi (sesskey, "ApplicationCursorKeys", 0, &cfg.app_cursor);
222 gppi (sesskey, "ApplicationKeypad", 0, &cfg.app_keypad);
223 gppi (sesskey, "NetHackKeypad", 0, &cfg.nethack_keypad);
224 gppi (sesskey, "AltF4", 1, &cfg.alt_f4);
225 gppi (sesskey, "AltSpace", 0, &cfg.alt_space);
226 gppi (sesskey, "LdiscTerm", 0, &cfg.ldisc_term);
227 gppi (sesskey, "BlinkCur", 0, &cfg.blink_cur);
228 gppi (sesskey, "Beep", 1, &cfg.beep);
229 gppi (sesskey, "ScrollbackLines", 200, &cfg.savelines);
230 gppi (sesskey, "DECOriginMode", 0, &cfg.dec_om);
231 gppi (sesskey, "AutoWrapMode", 1, &cfg.wrap_mode);
232 gppi (sesskey, "LFImpliesCR", 0, &cfg.lfhascr);
233 gppi (sesskey, "WinNameAlways", 0, &cfg.win_name_always);
234 gpps (sesskey, "WinTitle", "", cfg.wintitle, sizeof(cfg.wintitle));
235 gppi (sesskey, "TermWidth", 80, &cfg.width);
236 gppi (sesskey, "TermHeight", 24, &cfg.height);
237 gpps (sesskey, "Font", "Courier", cfg.font, sizeof(cfg.font));
238 gppi (sesskey, "FontIsBold", 0, &cfg.fontisbold);
239 gppi (sesskey, "FontCharSet", ANSI_CHARSET, &cfg.fontcharset);
240 gppi (sesskey, "FontHeight", 10, &cfg.fontheight);
241 gppi (sesskey, "FontVTMode", VT_OEMANSI, (int *)&cfg.vtmode);
242 gppi (sesskey, "TryPalette", 0, &cfg.try_palette);
243 gppi (sesskey, "BoldAsColour", 1, &cfg.bold_colour);
244 for (i=0; i<22; i++) {
245 static char *defaults[] = {
246 "187,187,187", "255,255,255", "0,0,0", "85,85,85", "0,0,0",
247 "0,255,0", "0,0,0", "85,85,85", "187,0,0", "255,85,85",
248 "0,187,0", "85,255,85", "187,187,0", "255,255,85", "0,0,187",
249 "85,85,255", "187,0,187", "255,85,255", "0,187,187",
250 "85,255,255", "187,187,187", "255,255,255"
251 };
252 char buf[20], buf2[30];
253 int c0, c1, c2;
254 sprintf(buf, "Colour%d", i);
255 gpps (sesskey, buf, defaults[i], buf2, sizeof(buf2));
256 if(sscanf(buf2, "%d,%d,%d", &c0, &c1, &c2) == 3) {
257 cfg.colours[i][0] = c0;
258 cfg.colours[i][1] = c1;
259 cfg.colours[i][2] = c2;
260 }
261 }
262 gppi (sesskey, "MouseIsXterm", 0, &cfg.mouse_is_xterm);
263 for (i=0; i<256; i+=32) {
264 static char *defaults[] = {
265 "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",
266 "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",
267 "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",
268 "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",
269 "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",
270 "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",
271 "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",
272 "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"
273 };
274 char buf[20], buf2[256], *p;
275 int j;
276 sprintf(buf, "Wordness%d", i);
277 gpps (sesskey, buf, defaults[i/32], buf2, sizeof(buf2));
278 p = buf2;
279 for (j=i; j<i+32; j++) {
280 char *q = p;
281 while (*p && *p != ',') p++;
282 if (*p == ',') *p++ = '\0';
283 cfg.wordness[j] = atoi(q);
284 }
285 }
286 gppi (sesskey, "KoiWinXlat", 0, &cfg.xlat_enablekoiwin);
287 gppi (sesskey, "88592Xlat", 0, &cfg.xlat_88592w1250);
288 gppi (sesskey, "CapsLockCyr", 0, &cfg.xlat_capslockcyr);
289 gppi (sesskey, "ScrollBar", 1, &cfg.scrollbar);
290 gppi (sesskey, "ScrollOnKey", 0, &cfg.scroll_on_key);
291 gppi (sesskey, "LockSize", 0, &cfg.locksize);
292 gppi (sesskey, "BCE", 0, &cfg.bce);
293 gppi (sesskey, "BlinkText", 0, &cfg.blinktext);
294
295 close_settings_r(sesskey);
296 }
297
298 static void force_normal(HWND hwnd)
299 {
300 static int recurse = 0;
301
302 WINDOWPLACEMENT wp;
303
304 if(recurse) return;
305 recurse = 1;
306
307 wp.length = sizeof(wp);
308 if (GetWindowPlacement(hwnd, &wp))
309 {
310 wp.showCmd = SW_SHOWNORMAL;
311 SetWindowPlacement(hwnd, &wp);
312 }
313 recurse = 0;
314 }
315
316 static void MyGetDlgItemInt (HWND hwnd, int id, int *result) {
317 BOOL ok;
318 int n;
319 n = GetDlgItemInt (hwnd, id, &ok, FALSE);
320 if (ok)
321 *result = n;
322 }
323
324 static int CALLBACK LogProc (HWND hwnd, UINT msg,
325 WPARAM wParam, LPARAM lParam) {
326 int i;
327
328 switch (msg) {
329 case WM_INITDIALOG:
330 for (i=0; i<nevents; i++)
331 SendDlgItemMessage (hwnd, IDN_LIST, LB_ADDSTRING,
332 0, (LPARAM)events[i]);
333 return 1;
334 /* case WM_CTLCOLORDLG: */
335 /* return (int) GetStockObject (LTGRAY_BRUSH); */
336 case WM_COMMAND:
337 switch (LOWORD(wParam)) {
338 case IDOK:
339 logbox = NULL;
340 DestroyWindow (hwnd);
341 return 0;
342 case IDN_COPY:
343 if (HIWORD(wParam) == BN_CLICKED ||
344 HIWORD(wParam) == BN_DOUBLECLICKED) {
345 int selcount;
346 int *selitems;
347 selcount = SendDlgItemMessage(hwnd, IDN_LIST,
348 LB_GETSELCOUNT, 0, 0);
349 selitems = malloc(selcount * sizeof(int));
350 if (selitems) {
351 int count = SendDlgItemMessage(hwnd, IDN_LIST,
352 LB_GETSELITEMS,
353 selcount, (LPARAM)selitems);
354 int i;
355 int size;
356 char *clipdata;
357 static unsigned char sel_nl[] = SEL_NL;
358
359 size = 0;
360 for (i = 0; i < count; i++)
361 size += strlen(events[selitems[i]]) + sizeof(sel_nl);
362
363 clipdata = malloc(size);
364 if (clipdata) {
365 char *p = clipdata;
366 for (i = 0; i < count; i++) {
367 char *q = events[selitems[i]];
368 int qlen = strlen(q);
369 memcpy(p, q, qlen);
370 p += qlen;
371 memcpy(p, sel_nl, sizeof(sel_nl));
372 p += sizeof(sel_nl);
373 }
374 write_clip(clipdata, size);
375 term_deselect();
376 free(clipdata);
377 }
378 free(selitems);
379 }
380 }
381 return 0;
382 }
383 return 0;
384 case WM_CLOSE:
385 logbox = NULL;
386 DestroyWindow (hwnd);
387 return 0;
388 }
389 return 0;
390 }
391
392 static int CALLBACK LicenceProc (HWND hwnd, UINT msg,
393 WPARAM wParam, LPARAM lParam) {
394 switch (msg) {
395 case WM_INITDIALOG:
396 return 1;
397 case WM_COMMAND:
398 switch (LOWORD(wParam)) {
399 case IDOK:
400 EndDialog(hwnd, 1);
401 return 0;
402 }
403 return 0;
404 case WM_CLOSE:
405 EndDialog(hwnd, 1);
406 return 0;
407 }
408 return 0;
409 }
410
411 static int CALLBACK AboutProc (HWND hwnd, UINT msg,
412 WPARAM wParam, LPARAM lParam) {
413 switch (msg) {
414 case WM_INITDIALOG:
415 SetDlgItemText (hwnd, IDA_VERSION, ver);
416 return 1;
417 /* case WM_CTLCOLORDLG: */
418 /* return (int) GetStockObject (LTGRAY_BRUSH); */
419 /* case WM_CTLCOLORSTATIC: */
420 /* SetBkColor ((HDC)wParam, RGB(192,192,192)); */
421 /* return (int) GetStockObject (LTGRAY_BRUSH); */
422 case WM_COMMAND:
423 switch (LOWORD(wParam)) {
424 case IDOK:
425 abtbox = NULL;
426 DestroyWindow (hwnd);
427 return 0;
428 case IDA_LICENCE:
429 EnableWindow(hwnd, 0);
430 DialogBox (hinst, MAKEINTRESOURCE(IDD_LICENCEBOX),
431 NULL, LicenceProc);
432 EnableWindow(hwnd, 1);
433 SetActiveWindow(hwnd);
434 return 0;
435 }
436 return 0;
437 case WM_CLOSE:
438 abtbox = NULL;
439 DestroyWindow (hwnd);
440 return 0;
441 }
442 return 0;
443 }
444
445 /* ----------------------------------------------------------------------
446 * Routines to self-manage the controls in a dialog box.
447 */
448
449 #define GAPBETWEEN 3
450 #define GAPWITHIN 1
451 #define DLGWIDTH 168
452 #define STATICHEIGHT 8
453 #define CHECKBOXHEIGHT 8
454 #define RADIOHEIGHT 8
455 #define EDITHEIGHT 12
456 #define COMBOHEIGHT 12
457 #define PUSHBTNHEIGHT 14
458
459 struct ctlpos {
460 HWND hwnd;
461 LONG units;
462 WPARAM font;
463 int ypos, width;
464 };
465
466 /* Used on self-constructed dialogs. */
467 void ctlposinit(struct ctlpos *cp, HWND hwnd) {
468 RECT r;
469 cp->hwnd = hwnd;
470 cp->units = GetWindowLong(hwnd, GWL_USERDATA);
471 cp->font = GetWindowLong(hwnd, DWL_USER);
472 cp->ypos = GAPBETWEEN;
473 GetClientRect(hwnd, &r);
474 cp->width = (r.right * 4) / (cp->units & 0xFFFF) - 2*GAPBETWEEN;
475 }
476
477 /* Used on kosher dialogs. */
478 void ctlposinit2(struct ctlpos *cp, HWND hwnd) {
479 RECT r;
480 cp->hwnd = hwnd;
481 r.left = r.top = 0;
482 r.right = 4;
483 r.bottom = 8;
484 MapDialogRect(hwnd, &r);
485 cp->units = (r.bottom << 16) | r.right;
486 cp->font = SendMessage(hwnd, WM_GETFONT, 0, 0);
487 cp->ypos = GAPBETWEEN;
488 GetClientRect(hwnd, &r);
489 cp->width = (r.right * 4) / (cp->units & 0xFFFF) - 2*GAPBETWEEN;
490 }
491
492 void doctl(struct ctlpos *cp, RECT r, char *wclass, int wstyle, int exstyle,
493 char *wtext, int wid) {
494 HWND ctl;
495 /*
496 * Note nonstandard use of RECT. This is deliberate: by
497 * transforming the width and height directly we arrange to
498 * have all supposedly same-sized controls really same-sized.
499 */
500
501 /* MapDialogRect, or its near equivalent. */
502 r.left = (r.left * (cp->units & 0xFFFF)) / 4;
503 r.right = (r.right * (cp->units & 0xFFFF)) / 4;
504 r.top = (r.top * ((cp->units>>16) & 0xFFFF)) / 8;
505 r.bottom = (r.bottom * ((cp->units>>16) & 0xFFFF)) / 8;
506
507 ctl = CreateWindowEx(exstyle, wclass, wtext, wstyle,
508 r.left, r.top, r.right, r.bottom,
509 cp->hwnd, (HMENU)wid, hinst, NULL);
510 SendMessage(ctl, WM_SETFONT, cp->font, MAKELPARAM(TRUE, 0));
511 }
512
513 /*
514 * Some edit boxes. Each one has a static above it. The percentages
515 * of the horizontal space are provided.
516 */
517 void multiedit(struct ctlpos *cp, ...) {
518 RECT r;
519 va_list ap;
520 int percent, xpos;
521
522 percent = xpos = 0;
523 va_start(ap, cp);
524 while (1) {
525 char *text;
526 int staticid, editid, pcwidth;
527 text = va_arg(ap, char *);
528 if (!text)
529 break;
530 staticid = va_arg(ap, int);
531 editid = va_arg(ap, int);
532 pcwidth = va_arg(ap, int);
533
534 r.left = xpos + GAPBETWEEN;
535 percent += pcwidth;
536 xpos = (cp->width + GAPBETWEEN) * percent / 100;
537 r.right = xpos - r.left;
538
539 r.top = cp->ypos; r.bottom = STATICHEIGHT;
540 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0,
541 text, staticid);
542 r.top = cp->ypos + 8 + GAPWITHIN; r.bottom = EDITHEIGHT;
543 doctl(cp, r, "EDIT",
544 WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
545 WS_EX_CLIENTEDGE,
546 "", editid);
547 }
548 va_end(ap);
549 cp->ypos += 8+GAPWITHIN+12+GAPBETWEEN;
550 }
551
552 /*
553 * A set of radio buttons on the same line, with a static above
554 * them. `nacross' dictates how many parts the line is divided into
555 * (you might want this not to equal the number of buttons if you
556 * needed to line up some 2s and some 3s to look good in the same
557 * panel).
558 */
559 void radioline(struct ctlpos *cp, char *text, int id, int nacross, ...) {
560 RECT r;
561 va_list ap;
562 int group;
563 int i;
564
565 r.left = GAPBETWEEN; r.top = cp->ypos;
566 r.right = cp->width; r.bottom = STATICHEIGHT;
567 cp->ypos += r.bottom + GAPWITHIN;
568 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, text, id);
569 va_start(ap, nacross);
570 group = WS_GROUP;
571 i = 0;
572 while (1) {
573 char *btext;
574 int bid;
575 btext = va_arg(ap, char *);
576 if (!btext)
577 break;
578 bid = va_arg(ap, int);
579 r.left = GAPBETWEEN + i * (cp->width+GAPBETWEEN)/nacross;
580 r.right = (i+1) * (cp->width+GAPBETWEEN)/nacross - r.left;
581 r.top = cp->ypos; r.bottom = RADIOHEIGHT;
582 doctl(cp, r, "BUTTON",
583 BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP | group,
584 0,
585 btext, bid);
586 group = 0;
587 i++;
588 }
589 va_end(ap);
590 cp->ypos += r.bottom + GAPBETWEEN;
591 }
592
593 /*
594 * A set of radio buttons on multiple lines, with a static above
595 * them.
596 */
597 void radiobig(struct ctlpos *cp, char *text, int id, ...) {
598 RECT r;
599 va_list ap;
600 int group;
601
602 r.left = GAPBETWEEN; r.top = cp->ypos;
603 r.right = cp->width; r.bottom = STATICHEIGHT;
604 cp->ypos += r.bottom + GAPWITHIN;
605 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, text, id);
606 va_start(ap, id);
607 group = WS_GROUP;
608 while (1) {
609 char *btext;
610 int bid;
611 btext = va_arg(ap, char *);
612 if (!btext)
613 break;
614 bid = va_arg(ap, int);
615 r.left = GAPBETWEEN; r.top = cp->ypos;
616 r.right = cp->width; r.bottom = STATICHEIGHT;
617 cp->ypos += r.bottom + GAPWITHIN;
618 doctl(cp, r, "BUTTON",
619 BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP | group,
620 0,
621 btext, bid);
622 group = 0;
623 }
624 va_end(ap);
625 cp->ypos += GAPBETWEEN - GAPWITHIN;
626 }
627
628 /*
629 * A single standalone checkbox.
630 */
631 void checkbox(struct ctlpos *cp, char *text, int id) {
632 RECT r;
633
634 r.left = GAPBETWEEN; r.top = cp->ypos;
635 r.right = cp->width; r.bottom = CHECKBOXHEIGHT;
636 cp->ypos += r.bottom + GAPBETWEEN;
637 doctl(cp, r, "BUTTON",
638 BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0,
639 text, id);
640 }
641
642 /*
643 * A button on the right hand side, with a static to its left.
644 */
645 void staticbtn(struct ctlpos *cp, char *stext, int sid, char *btext, int bid) {
646 const int height = (PUSHBTNHEIGHT > STATICHEIGHT ?
647 PUSHBTNHEIGHT : STATICHEIGHT);
648 RECT r;
649 int lwid, rwid, rpos;
650
651 rpos = GAPBETWEEN + 3 * (cp->width + GAPBETWEEN) / 4;
652 lwid = rpos - 2*GAPBETWEEN;
653 rwid = cp->width + GAPBETWEEN - rpos;
654
655 r.left = GAPBETWEEN; r.top = cp->ypos + (height-STATICHEIGHT)/2;
656 r.right = lwid; r.bottom = STATICHEIGHT;
657 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
658
659 r.left = rpos; r.top = cp->ypos + (height-PUSHBTNHEIGHT)/2;
660 r.right = rwid; r.bottom = PUSHBTNHEIGHT;
661 doctl(cp, r, "BUTTON",
662 WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
663 0,
664 btext, bid);
665
666 cp->ypos += height + GAPBETWEEN;
667 }
668
669 /*
670 * An edit control on the right hand side, with a static to its left.
671 */
672 void staticedit(struct ctlpos *cp, char *stext, int sid, int eid) {
673 const int height = (EDITHEIGHT > STATICHEIGHT ?
674 EDITHEIGHT : STATICHEIGHT);
675 RECT r;
676 int lwid, rwid, rpos;
677
678 rpos = GAPBETWEEN + (cp->width + GAPBETWEEN) / 2;
679 lwid = rpos - 2*GAPBETWEEN;
680 rwid = cp->width + GAPBETWEEN - rpos;
681
682 r.left = GAPBETWEEN; r.top = cp->ypos + (height-STATICHEIGHT)/2;
683 r.right = lwid; r.bottom = STATICHEIGHT;
684 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
685
686 r.left = rpos; r.top = cp->ypos + (height-EDITHEIGHT)/2;
687 r.right = rwid; r.bottom = EDITHEIGHT;
688 doctl(cp, r, "EDIT",
689 WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
690 WS_EX_CLIENTEDGE,
691 "", eid);
692
693 cp->ypos += height + GAPBETWEEN;
694 }
695
696 /*
697 * A tab-control substitute when a real tab control is unavailable.
698 */
699 void ersatztab(struct ctlpos *cp, char *stext, int sid, int lid, int s2id) {
700 const int height = (COMBOHEIGHT > STATICHEIGHT ?
701 COMBOHEIGHT : STATICHEIGHT);
702 RECT r;
703 int bigwid, lwid, rwid, rpos;
704 static const int BIGGAP = 15;
705 static const int MEDGAP = 3;
706
707 bigwid = cp->width + 2*GAPBETWEEN - 2*BIGGAP;
708 cp->ypos += MEDGAP;
709 rpos = BIGGAP + (bigwid + BIGGAP) / 2;
710 lwid = rpos - 2*BIGGAP;
711 rwid = bigwid + BIGGAP - rpos;
712
713 r.left = BIGGAP; r.top = cp->ypos + (height-STATICHEIGHT)/2;
714 r.right = lwid; r.bottom = STATICHEIGHT;
715 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
716
717 r.left = rpos; r.top = cp->ypos + (height-COMBOHEIGHT)/2;
718 r.right = rwid; r.bottom = COMBOHEIGHT*10;
719 doctl(cp, r, "COMBOBOX",
720 WS_CHILD | WS_VISIBLE | WS_TABSTOP |
721 CBS_DROPDOWNLIST | CBS_HASSTRINGS,
722 WS_EX_CLIENTEDGE,
723 "", lid);
724
725 cp->ypos += height + MEDGAP + GAPBETWEEN;
726
727 r.left = GAPBETWEEN; r.top = cp->ypos;
728 r.right = cp->width; r.bottom = 2;
729 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE | SS_ETCHEDHORZ,
730 0, "", s2id);
731 }
732
733 /*
734 * A static line, followed by an edit control on the left hand side
735 * and a button on the right.
736 */
737 void editbutton(struct ctlpos *cp, char *stext, int sid,
738 int eid, char *btext, int bid) {
739 const int height = (EDITHEIGHT > PUSHBTNHEIGHT ?
740 EDITHEIGHT : PUSHBTNHEIGHT);
741 RECT r;
742 int lwid, rwid, rpos;
743
744 r.left = GAPBETWEEN; r.top = cp->ypos;
745 r.right = cp->width; r.bottom = STATICHEIGHT;
746 cp->ypos += r.bottom + GAPWITHIN;
747 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
748
749 rpos = GAPBETWEEN + 3 * (cp->width + GAPBETWEEN) / 4;
750 lwid = rpos - 2*GAPBETWEEN;
751 rwid = cp->width + GAPBETWEEN - rpos;
752
753 r.left = GAPBETWEEN; r.top = cp->ypos + (height-EDITHEIGHT)/2;
754 r.right = lwid; r.bottom = EDITHEIGHT;
755 doctl(cp, r, "EDIT",
756 WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
757 WS_EX_CLIENTEDGE,
758 "", eid);
759
760 r.left = rpos; r.top = cp->ypos + (height-PUSHBTNHEIGHT)/2;
761 r.right = rwid; r.bottom = PUSHBTNHEIGHT;
762 doctl(cp, r, "BUTTON",
763 WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
764 0,
765 btext, bid);
766
767 cp->ypos += height + GAPBETWEEN;
768 }
769
770 /*
771 * Special control which was hard to describe generically: the
772 * session-saver assembly. A static; below that an edit box; below
773 * that a list box. To the right of the list box, a column of
774 * buttons.
775 */
776 void sesssaver(struct ctlpos *cp, char *text,
777 int staticid, int editid, int listid, ...) {
778 RECT r;
779 va_list ap;
780 int lwid, rwid, rpos;
781 int y;
782 const int LISTDEFHEIGHT = 66;
783
784 rpos = GAPBETWEEN + 3 * (cp->width + GAPBETWEEN) / 4;
785 lwid = rpos - 2*GAPBETWEEN;
786 rwid = cp->width + GAPBETWEEN - rpos;
787
788 /* The static control. */
789 r.left = GAPBETWEEN; r.top = cp->ypos;
790 r.right = lwid; r.bottom = STATICHEIGHT;
791 cp->ypos += r.bottom + GAPWITHIN;
792 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, text, staticid);
793
794 /* The edit control. */
795 r.left = GAPBETWEEN; r.top = cp->ypos;
796 r.right = lwid; r.bottom = EDITHEIGHT;
797 cp->ypos += r.bottom + GAPWITHIN;
798 doctl(cp, r, "EDIT",
799 WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
800 WS_EX_CLIENTEDGE,
801 "", staticid);
802
803 /*
804 * The buttons (we should hold off on the list box until we
805 * know how big the buttons are).
806 */
807 va_start(ap, listid);
808 y = cp->ypos;
809 while (1) {
810 char *btext = va_arg(ap, char *);
811 int bid;
812 if (!btext) break;
813 bid = va_arg(ap, int);
814 r.left = rpos; r.top = y;
815 r.right = rwid; r.bottom = PUSHBTNHEIGHT;
816 y += r.bottom + GAPWITHIN;
817 doctl(cp, r, "BUTTON",
818 WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
819 0,
820 btext, bid);
821 }
822
823 /* Compute list box height. LISTDEFHEIGHT, or height of buttons. */
824 y -= cp->ypos;
825 y -= GAPWITHIN;
826 if (y < LISTDEFHEIGHT) y = LISTDEFHEIGHT;
827 r.left = GAPBETWEEN; r.top = cp->ypos;
828 r.right = lwid; r.bottom = y;
829 cp->ypos += y + GAPBETWEEN;
830 doctl(cp, r, "LISTBOX",
831 WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL | LBS_HASSTRINGS,
832 WS_EX_CLIENTEDGE,
833 "", listid);
834 }
835
836 /*
837 * Another special control: the environment-variable setter. A
838 * static line first; then a pair of edit boxes with associated
839 * statics, and two buttons; then a list box.
840 */
841 void envsetter(struct ctlpos *cp, char *stext, int sid,
842 char *e1stext, int e1sid, int e1id,
843 char *e2stext, int e2sid, int e2id,
844 int listid, char *b1text, int b1id, char *b2text, int b2id) {
845 RECT r;
846 const int height = (STATICHEIGHT > EDITHEIGHT && STATICHEIGHT > PUSHBTNHEIGHT ?
847 STATICHEIGHT :
848 EDITHEIGHT > PUSHBTNHEIGHT ?
849 EDITHEIGHT : PUSHBTNHEIGHT);
850 const static int percents[] = { 20, 35, 10, 25 };
851 int i, j, xpos, percent;
852 const int LISTHEIGHT = 42;
853
854 /* The static control. */
855 r.left = GAPBETWEEN; r.top = cp->ypos;
856 r.right = cp->width; r.bottom = STATICHEIGHT;
857 cp->ypos += r.bottom + GAPWITHIN;
858 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
859
860 /* The statics+edits+buttons. */
861 for (j = 0; j < 2; j++) {
862 percent = 10;
863 for (i = 0; i < 4; i++) {
864 xpos = (cp->width + GAPBETWEEN) * percent / 100;
865 r.left = xpos + GAPBETWEEN;
866 percent += percents[i];
867 xpos = (cp->width + GAPBETWEEN) * percent / 100;
868 r.right = xpos - r.left;
869 r.top = cp->ypos;
870 r.bottom = (i==0 ? STATICHEIGHT :
871 i==1 ? EDITHEIGHT :
872 PUSHBTNHEIGHT);
873 r.top += (height-r.bottom)/2;
874 if (i==0) {
875 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0,
876 j==0 ? e1stext : e2stext, j==0 ? e1sid : e2sid);
877 } else if (i==1) {
878 doctl(cp, r, "EDIT",
879 WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
880 WS_EX_CLIENTEDGE,
881 "", j==0 ? e1id : e2id);
882 } else if (i==3) {
883 doctl(cp, r, "BUTTON",
884 WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
885 0,
886 j==0 ? b1text : b2text, j==0 ? b1id : b2id);
887 }
888 }
889 cp->ypos += height + GAPWITHIN;
890 }
891
892 /* The list box. */
893 r.left = GAPBETWEEN; r.top = cp->ypos;
894 r.right = cp->width; r.bottom = LISTHEIGHT;
895 cp->ypos += r.bottom + GAPBETWEEN;
896 doctl(cp, r, "LISTBOX",
897 WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL | LBS_HASSTRINGS |
898 LBS_USETABSTOPS,
899 WS_EX_CLIENTEDGE,
900 "", listid);
901 }
902
903 /*
904 * Yet another special control: the character-class setter. A
905 * static, then a list, then a line containing a
906 * button-and-static-and-edit.
907 */
908 void charclass(struct ctlpos *cp, char *stext, int sid, int listid,
909 char *btext, int bid, int eid, char *s2text, int s2id) {
910 RECT r;
911 const int height = (STATICHEIGHT > EDITHEIGHT && STATICHEIGHT > PUSHBTNHEIGHT ?
912 STATICHEIGHT :
913 EDITHEIGHT > PUSHBTNHEIGHT ?
914 EDITHEIGHT : PUSHBTNHEIGHT);
915 const static int percents[] = { 30, 40, 30 };
916 int i, xpos, percent;
917 const int LISTHEIGHT = 66;
918
919 /* The static control. */
920 r.left = GAPBETWEEN; r.top = cp->ypos;
921 r.right = cp->width; r.bottom = STATICHEIGHT;
922 cp->ypos += r.bottom + GAPWITHIN;
923 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
924
925 /* The list box. */
926 r.left = GAPBETWEEN; r.top = cp->ypos;
927 r.right = cp->width; r.bottom = LISTHEIGHT;
928 cp->ypos += r.bottom + GAPWITHIN;
929 doctl(cp, r, "LISTBOX",
930 WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL | LBS_HASSTRINGS |
931 LBS_USETABSTOPS,
932 WS_EX_CLIENTEDGE,
933 "", listid);
934
935 /* The button+static+edit. */
936 percent = xpos = 0;
937 for (i = 0; i < 3; i++) {
938 r.left = xpos + GAPBETWEEN;
939 percent += percents[i];
940 xpos = (cp->width + GAPBETWEEN) * percent / 100;
941 r.right = xpos - r.left;
942 r.top = cp->ypos;
943 r.bottom = (i==0 ? PUSHBTNHEIGHT :
944 i==1 ? STATICHEIGHT :
945 EDITHEIGHT);
946 r.top += (height-r.bottom)/2;
947 if (i==0) {
948 doctl(cp, r, "BUTTON",
949 WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
950 0, btext, bid);
951 } else if (i==1) {
952 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE | SS_CENTER,
953 0, s2text, s2id);
954 } else if (i==2) {
955 doctl(cp, r, "EDIT",
956 WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
957 WS_EX_CLIENTEDGE, "", eid);
958 }
959 }
960 cp->ypos += height + GAPBETWEEN;
961 }
962
963 /*
964 * A special control (horrors!). The colour editor. A static line;
965 * then on the left, a list box, and on the right, a sequence of
966 * two-part statics followed by a button.
967 */
968 void colouredit(struct ctlpos *cp, char *stext, int sid, int listid,
969 char *btext, int bid, ...) {
970 RECT r;
971 int y;
972 va_list ap;
973 int lwid, rwid, rpos;
974 const int LISTHEIGHT = 66;
975
976 /* The static control. */
977 r.left = GAPBETWEEN; r.top = cp->ypos;
978 r.right = cp->width; r.bottom = STATICHEIGHT;
979 cp->ypos += r.bottom + GAPWITHIN;
980 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
981
982 rpos = GAPBETWEEN + 2 * (cp->width + GAPBETWEEN) / 3;
983 lwid = rpos - 2*GAPBETWEEN;
984 rwid = cp->width + GAPBETWEEN - rpos;
985
986 /* The list box. */
987 r.left = GAPBETWEEN; r.top = cp->ypos;
988 r.right = lwid; r.bottom = LISTHEIGHT;
989 doctl(cp, r, "LISTBOX",
990 WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL | LBS_HASSTRINGS |
991 LBS_USETABSTOPS,
992 WS_EX_CLIENTEDGE,
993 "", listid);
994
995 /* The statics. */
996 y = cp->ypos;
997 va_start(ap, bid);
998 while (1) {
999 char *ltext;
1000 int lid, rid;
1001 ltext = va_arg(ap, char *);
1002 if (!ltext) break;
1003 lid = va_arg(ap, int);
1004 rid = va_arg(ap, int);
1005 r.top = y; r.bottom = STATICHEIGHT;
1006 y += r.bottom + GAPWITHIN;
1007 r.left = rpos; r.right = rwid/2;
1008 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, ltext, lid);
1009 r.left = rpos + r.right; r.right = rwid - r.right;
1010 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE | SS_RIGHT, 0, "", rid);
1011 }
1012 va_end(ap);
1013
1014 /* The button. */
1015 r.top = y + 2*GAPWITHIN; r.bottom = PUSHBTNHEIGHT;
1016 r.left = rpos; r.right = rwid;
1017 doctl(cp, r, "BUTTON",
1018 WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
1019 0, btext, bid);
1020
1021 cp->ypos += LISTHEIGHT + GAPBETWEEN;
1022 }
1023
1024 static int GeneralPanelProc (HWND hwnd, UINT msg,
1025 WPARAM wParam, LPARAM lParam) {
1026 switch (msg) {
1027 case WM_SETFONT:
1028 {
1029 HFONT hfont = (HFONT)wParam;
1030 HFONT oldfont;
1031 HDC hdc;
1032 TEXTMETRIC tm;
1033 LONG units;
1034
1035 hdc = GetDC(hwnd);
1036 oldfont = SelectObject(hdc, hfont);
1037 GetTextMetrics(hdc, &tm);
1038 units = (tm.tmHeight << 16) | tm.tmAveCharWidth;
1039 SelectObject(hdc, oldfont);
1040 DeleteDC(hdc);
1041 SetWindowLong(hwnd, GWL_USERDATA, units);
1042 SetWindowLong(hwnd, DWL_USER, wParam);
1043 }
1044 return 0;
1045 case WM_INITDIALOG:
1046 SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
1047 return 1;
1048 case WM_CLOSE:
1049 DestroyWindow (hwnd);
1050 return 1;
1051 }
1052 return 0;
1053 }
1054
1055 static char savedsession[2048];
1056
1057 static int CALLBACK ConnectionProc (HWND hwnd, UINT msg,
1058 WPARAM wParam, LPARAM lParam) {
1059 int i;
1060 struct ctlpos cp;
1061
1062 switch (msg) {
1063 case WM_INITDIALOG:
1064 /* Accelerators used: [aco] dehlnprstwx */
1065 ctlposinit(&cp, hwnd);
1066 multiedit(&cp,
1067 "Host &Name", IDC0_HOSTSTATIC, IDC0_HOST, 75,
1068 "&Port", IDC0_PORTSTATIC, IDC0_PORT, 25, NULL);
1069 radioline(&cp, "Protocol:", IDC0_PROTSTATIC, 3,
1070 "&Raw", IDC0_PROTRAW,
1071 "&Telnet", IDC0_PROTTELNET,
1072 #ifdef FWHACK
1073 "SS&H/hack",
1074 #else
1075 "SS&H",
1076 #endif
1077 IDC0_PROTSSH, NULL);
1078 sesssaver(&cp, "Stor&ed Sessions",
1079 IDC0_SESSSTATIC, IDC0_SESSEDIT, IDC0_SESSLIST,
1080 "&Load", IDC0_SESSLOAD,
1081 "&Save", IDC0_SESSSAVE,
1082 "&Delete", IDC0_SESSDEL, NULL);
1083 checkbox(&cp, "Close Window on E&xit", IDC0_CLOSEEXIT);
1084 checkbox(&cp, "&Warn on Close", IDC0_CLOSEWARN);
1085
1086 SetDlgItemText (hwnd, IDC0_HOST, cfg.host);
1087 SetDlgItemText (hwnd, IDC0_SESSEDIT, savedsession);
1088 SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE);
1089 for (i = 0; i < nsessions; i++)
1090 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING,
1091 0, (LPARAM) (sessions[i]));
1092 CheckRadioButton (hwnd, IDC0_PROTRAW, IDC0_PROTSSH,
1093 cfg.protocol==PROT_SSH ? IDC0_PROTSSH :
1094 cfg.protocol==PROT_TELNET ? IDC0_PROTTELNET : IDC0_PROTRAW );
1095 CheckDlgButton (hwnd, IDC0_CLOSEEXIT, cfg.close_on_exit);
1096 CheckDlgButton (hwnd, IDC0_CLOSEWARN, cfg.warn_on_close);
1097 break;
1098 case WM_LBUTTONUP:
1099 /*
1100 * Button release should trigger WM_OK if there was a
1101 * previous double click on the session list.
1102 */
1103 ReleaseCapture();
1104 if (readytogo)
1105 SendMessage (GetParent(hwnd), WM_COMMAND, IDOK, 0);
1106 break;
1107 case WM_COMMAND:
1108 switch (LOWORD(wParam)) {
1109 case IDC0_PROTTELNET:
1110 case IDC0_PROTSSH:
1111 case IDC0_PROTRAW:
1112 if (HIWORD(wParam) == BN_CLICKED ||
1113 HIWORD(wParam) == BN_DOUBLECLICKED) {
1114 int i = IsDlgButtonChecked (hwnd, IDC0_PROTSSH);
1115 int j = IsDlgButtonChecked (hwnd, IDC0_PROTTELNET);
1116 cfg.protocol = i ? PROT_SSH : j ? PROT_TELNET : PROT_RAW ;
1117 if ((cfg.protocol == PROT_SSH && cfg.port == 23) ||
1118 (cfg.protocol == PROT_TELNET && cfg.port == 22)) {
1119 cfg.port = i ? 22 : 23;
1120 SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE);
1121 }
1122 }
1123 break;
1124 case IDC0_HOST:
1125 if (HIWORD(wParam) == EN_CHANGE)
1126 GetDlgItemText (hwnd, IDC0_HOST, cfg.host,
1127 sizeof(cfg.host)-1);
1128 break;
1129 case IDC0_PORT:
1130 if (HIWORD(wParam) == EN_CHANGE)
1131 MyGetDlgItemInt (hwnd, IDC0_PORT, &cfg.port);
1132 break;
1133 case IDC0_CLOSEEXIT:
1134 if (HIWORD(wParam) == BN_CLICKED ||
1135 HIWORD(wParam) == BN_DOUBLECLICKED)
1136 cfg.close_on_exit = IsDlgButtonChecked (hwnd, IDC0_CLOSEEXIT);
1137 break;
1138 case IDC0_CLOSEWARN:
1139 if (HIWORD(wParam) == BN_CLICKED ||
1140 HIWORD(wParam) == BN_DOUBLECLICKED)
1141 cfg.warn_on_close = IsDlgButtonChecked (hwnd, IDC0_CLOSEWARN);
1142 break;
1143 case IDC0_SESSEDIT:
1144 if (HIWORD(wParam) == EN_CHANGE) {
1145 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
1146 (WPARAM) -1, 0);
1147 GetDlgItemText (hwnd, IDC0_SESSEDIT,
1148 savedsession, sizeof(savedsession)-1);
1149 savedsession[sizeof(savedsession)-1] = '\0';
1150 }
1151 break;
1152 case IDC0_SESSSAVE:
1153 if (HIWORD(wParam) == BN_CLICKED ||
1154 HIWORD(wParam) == BN_DOUBLECLICKED) {
1155 /*
1156 * Save a session
1157 */
1158 char str[2048];
1159 GetDlgItemText (hwnd, IDC0_SESSEDIT, str, sizeof(str)-1);
1160 if (!*str) {
1161 int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
1162 LB_GETCURSEL, 0, 0);
1163 if (n == LB_ERR) {
1164 MessageBeep(0);
1165 break;
1166 }
1167 strcpy (str, sessions[n]);
1168 }
1169 save_settings (str, !!strcmp(str, "Default Settings"));
1170 get_sesslist (FALSE);
1171 get_sesslist (TRUE);
1172 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_RESETCONTENT,
1173 0, 0);
1174 for (i = 0; i < nsessions; i++)
1175 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING,
1176 0, (LPARAM) (sessions[i]));
1177 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
1178 (WPARAM) -1, 0);
1179 }
1180 break;
1181 case IDC0_SESSLIST:
1182 case IDC0_SESSLOAD:
1183 if (LOWORD(wParam) == IDC0_SESSLOAD &&
1184 HIWORD(wParam) != BN_CLICKED &&
1185 HIWORD(wParam) != BN_DOUBLECLICKED)
1186 break;
1187 if (LOWORD(wParam) == IDC0_SESSLIST &&
1188 HIWORD(wParam) != LBN_DBLCLK)
1189 break;
1190 {
1191 int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
1192 LB_GETCURSEL, 0, 0);
1193 if (n == LB_ERR) {
1194 MessageBeep(0);
1195 break;
1196 }
1197 load_settings (sessions[n],
1198 !!strcmp(sessions[n], "Default Settings"));
1199 SetDlgItemText (hwnd, IDC0_HOST, cfg.host);
1200 SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE);
1201 CheckRadioButton (hwnd, IDC0_PROTRAW, IDC0_PROTSSH,
1202 (cfg.protocol==PROT_SSH ? IDC0_PROTSSH :
1203 cfg.protocol==PROT_TELNET ? IDC0_PROTTELNET : IDC0_PROTRAW));
1204 CheckDlgButton (hwnd, IDC0_CLOSEEXIT, cfg.close_on_exit);
1205 CheckDlgButton (hwnd, IDC0_CLOSEWARN, cfg.warn_on_close);
1206 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
1207 (WPARAM) -1, 0);
1208 }
1209 if (LOWORD(wParam) == IDC0_SESSLIST) {
1210 /*
1211 * A double-click on a saved session should
1212 * actually start the session, not just load it.
1213 * Unless it's Default Settings or some other
1214 * host-less set of saved settings.
1215 */
1216 if (*cfg.host) {
1217 readytogo = TRUE;
1218 SetCapture(hwnd);
1219 }
1220 }
1221 break;
1222 case IDC0_SESSDEL:
1223 if (HIWORD(wParam) == BN_CLICKED ||
1224 HIWORD(wParam) == BN_DOUBLECLICKED) {
1225 int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
1226 LB_GETCURSEL, 0, 0);
1227 if (n == LB_ERR || n == 0) {
1228 MessageBeep(0);
1229 break;
1230 }
1231 del_settings(sessions[n]);
1232 get_sesslist (FALSE);
1233 get_sesslist (TRUE);
1234 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_RESETCONTENT,
1235 0, 0);
1236 for (i = 0; i < nsessions; i++)
1237 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING,
1238 0, (LPARAM) (sessions[i]));
1239 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
1240 (WPARAM) -1, 0);
1241 }
1242 }
1243 }
1244 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1245 }
1246
1247 static int CALLBACK KeyboardProc (HWND hwnd, UINT msg,
1248 WPARAM wParam, LPARAM lParam) {
1249 struct ctlpos cp;
1250 switch (msg) {
1251 case WM_INITDIALOG:
1252 /* Accelerators used: [aco] 4?ehiklmnprsuvxy */
1253 ctlposinit(&cp, hwnd);
1254 radioline(&cp, "Action of Backspace:", IDC1_DELSTATIC, 2,
1255 "Control-&H", IDC1_DEL008,
1256 "Control-&? (127)", IDC1_DEL127, NULL);
1257 radioline(&cp, "Action of Home and End:", IDC1_HOMESTATIC, 2,
1258 "&Standard", IDC1_HOMETILDE,
1259 "&rxvt", IDC1_HOMERXVT, NULL);
1260 radioline(&cp, "Function key and keypad layout:", IDC1_FUNCSTATIC, 3,
1261 "&VT400", IDC1_FUNCTILDE,
1262 "&Linux", IDC1_FUNCLINUX,
1263 "&Xterm R6", IDC1_FUNCXTERM, NULL);
1264 radioline(&cp, "Initial state of cursor keys:", IDC1_CURSTATIC, 2,
1265 "&Normal", IDC1_CURNORMAL,
1266 "A&pplication", IDC1_CURAPPLIC, NULL);
1267 radioline(&cp, "Initial state of numeric keypad:", IDC1_KPSTATIC, 3,
1268 "Nor&mal", IDC1_KPNORMAL,
1269 "Appl&ication", IDC1_KPAPPLIC,
1270 "N&etHack", IDC1_KPNH, NULL);
1271 checkbox(&cp, "ALT-F&4 is special (closes window)", IDC1_ALTF4);
1272 checkbox(&cp, "ALT-Space is special (S&ystem menu)", IDC1_ALTSPACE);
1273 checkbox(&cp, "&Use local terminal line discipline", IDC1_LDISCTERM);
1274 checkbox(&cp, "Reset scrollback on &keypress", IDC1_SCROLLKEY);
1275
1276 CheckRadioButton (hwnd, IDC1_DEL008, IDC1_DEL127,
1277 cfg.bksp_is_delete ? IDC1_DEL127 : IDC1_DEL008);
1278 CheckRadioButton (hwnd, IDC1_HOMETILDE, IDC1_HOMERXVT,
1279 cfg.rxvt_homeend ? IDC1_HOMERXVT : IDC1_HOMETILDE);
1280 CheckRadioButton (hwnd, IDC1_FUNCTILDE, IDC1_FUNCXTERM,
1281 cfg.funky_type ?
1282 (cfg.funky_type==2 ? IDC1_FUNCXTERM
1283 : IDC1_FUNCLINUX )
1284 : IDC1_FUNCTILDE);
1285 CheckRadioButton (hwnd, IDC1_CURNORMAL, IDC1_CURAPPLIC,
1286 cfg.app_cursor ? IDC1_CURAPPLIC : IDC1_CURNORMAL);
1287 CheckRadioButton (hwnd, IDC1_KPNORMAL, IDC1_KPNH,
1288 cfg.nethack_keypad ? IDC1_KPNH :
1289 cfg.app_keypad ? IDC1_KPAPPLIC : IDC1_KPNORMAL);
1290 CheckDlgButton (hwnd, IDC1_ALTF4, cfg.alt_f4);
1291 CheckDlgButton (hwnd, IDC1_ALTSPACE, cfg.alt_space);
1292 CheckDlgButton (hwnd, IDC1_LDISCTERM, cfg.ldisc_term);
1293 CheckDlgButton (hwnd, IDC1_SCROLLKEY, cfg.scroll_on_key);
1294 break;
1295 case WM_COMMAND:
1296 if (HIWORD(wParam) == BN_CLICKED ||
1297 HIWORD(wParam) == BN_DOUBLECLICKED)
1298 switch (LOWORD(wParam)) {
1299 case IDC1_DEL008:
1300 case IDC1_DEL127:
1301 cfg.bksp_is_delete = IsDlgButtonChecked (hwnd, IDC1_DEL127);
1302 break;
1303 case IDC1_HOMETILDE:
1304 case IDC1_HOMERXVT:
1305 cfg.rxvt_homeend = IsDlgButtonChecked (hwnd, IDC1_HOMERXVT);
1306 break;
1307 case IDC1_FUNCXTERM:
1308 cfg.funky_type = 2;
1309 break;
1310 case IDC1_FUNCTILDE:
1311 case IDC1_FUNCLINUX:
1312 cfg.funky_type = IsDlgButtonChecked (hwnd, IDC1_FUNCLINUX);
1313 break;
1314 case IDC1_KPNORMAL:
1315 case IDC1_KPAPPLIC:
1316 cfg.app_keypad = IsDlgButtonChecked (hwnd, IDC1_KPAPPLIC);
1317 cfg.nethack_keypad = FALSE;
1318 break;
1319 case IDC1_KPNH:
1320 cfg.app_keypad = FALSE;
1321 cfg.nethack_keypad = TRUE;
1322 break;
1323 case IDC1_CURNORMAL:
1324 case IDC1_CURAPPLIC:
1325 cfg.app_cursor = IsDlgButtonChecked (hwnd, IDC1_CURAPPLIC);
1326 break;
1327 case IDC1_ALTF4:
1328 if (HIWORD(wParam) == BN_CLICKED ||
1329 HIWORD(wParam) == BN_DOUBLECLICKED)
1330 cfg.alt_f4 = IsDlgButtonChecked (hwnd, IDC1_ALTF4);
1331 break;
1332 case IDC1_ALTSPACE:
1333 if (HIWORD(wParam) == BN_CLICKED ||
1334 HIWORD(wParam) == BN_DOUBLECLICKED)
1335 cfg.alt_space = IsDlgButtonChecked (hwnd, IDC1_ALTSPACE);
1336 break;
1337 case IDC1_LDISCTERM:
1338 if (HIWORD(wParam) == BN_CLICKED ||
1339 HIWORD(wParam) == BN_DOUBLECLICKED)
1340 cfg.ldisc_term = IsDlgButtonChecked (hwnd, IDC1_LDISCTERM);
1341 break;
1342 case IDC1_SCROLLKEY:
1343 if (HIWORD(wParam) == BN_CLICKED ||
1344 HIWORD(wParam) == BN_DOUBLECLICKED)
1345 cfg.scroll_on_key = IsDlgButtonChecked (hwnd, IDC1_SCROLLKEY);
1346 break;
1347 }
1348 }
1349 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1350 }
1351
1352 static void fmtfont (char *buf) {
1353 sprintf (buf, "Font: %s, ", cfg.font);
1354 if (cfg.fontisbold)
1355 strcat(buf, "bold, ");
1356 if (cfg.fontheight == 0)
1357 strcat (buf, "default height");
1358 else
1359 sprintf (buf+strlen(buf), "%d-%s",
1360 (cfg.fontheight < 0 ? -cfg.fontheight : cfg.fontheight),
1361 (cfg.fontheight < 0 ? "pixel" : "point"));
1362 }
1363
1364 static int CALLBACK TerminalProc (HWND hwnd, UINT msg,
1365 WPARAM wParam, LPARAM lParam) {
1366 struct ctlpos cp;
1367 CHOOSEFONT cf;
1368 LOGFONT lf;
1369 char fontstatic[256];
1370
1371 switch (msg) {
1372 case WM_INITDIALOG:
1373 /* Accelerators used: [aco] dghlmnprsw */
1374 ctlposinit(&cp, hwnd);
1375 multiedit(&cp,
1376 "&Rows", IDC2_ROWSSTATIC, IDC2_ROWSEDIT, 33,
1377 "Colu&mns", IDC2_COLSSTATIC, IDC2_COLSEDIT, 33,
1378 "&Scrollback", IDC2_SAVESTATIC, IDC2_SAVEEDIT, 33,
1379 NULL);
1380 staticbtn(&cp, "", IDC2_FONTSTATIC, "C&hange...", IDC2_CHOOSEFONT);
1381 checkbox(&cp, "Auto &wrap mode initially on", IDC2_WRAPMODE);
1382 checkbox(&cp, "&DEC Origin Mode initially on", IDC2_DECOM);
1383 checkbox(&cp, "Implicit CR in every &LF", IDC2_LFHASCR);
1384 checkbox(&cp, "Bee&p enabled", IDC1_BEEP);
1385 checkbox(&cp, "Use Back&ground colour erase", IDC2_BCE);
1386 checkbox(&cp, "Enable bli&nking text", IDC2_BLINKTEXT);
1387
1388 CheckDlgButton (hwnd, IDC2_WRAPMODE, cfg.wrap_mode);
1389 CheckDlgButton (hwnd, IDC2_DECOM, cfg.dec_om);
1390 CheckDlgButton (hwnd, IDC2_LFHASCR, cfg.lfhascr);
1391 SetDlgItemInt (hwnd, IDC2_ROWSEDIT, cfg.height, FALSE);
1392 SetDlgItemInt (hwnd, IDC2_COLSEDIT, cfg.width, FALSE);
1393 SetDlgItemInt (hwnd, IDC2_SAVEEDIT, cfg.savelines, FALSE);
1394 fmtfont (fontstatic);
1395 SetDlgItemText (hwnd, IDC2_FONTSTATIC, fontstatic);
1396 CheckDlgButton (hwnd, IDC1_BEEP, cfg.beep);
1397 CheckDlgButton (hwnd, IDC2_BCE, cfg.bce);
1398 CheckDlgButton (hwnd, IDC2_BLINKTEXT, cfg.blinktext);
1399 break;
1400 case WM_COMMAND:
1401 switch (LOWORD(wParam)) {
1402 case IDC2_WRAPMODE:
1403 if (HIWORD(wParam) == BN_CLICKED ||
1404 HIWORD(wParam) == BN_DOUBLECLICKED)
1405 cfg.wrap_mode = IsDlgButtonChecked (hwnd, IDC2_WRAPMODE);
1406 break;
1407 case IDC2_DECOM:
1408 if (HIWORD(wParam) == BN_CLICKED ||
1409 HIWORD(wParam) == BN_DOUBLECLICKED)
1410 cfg.dec_om = IsDlgButtonChecked (hwnd, IDC2_DECOM);
1411 break;
1412 case IDC2_LFHASCR:
1413 if (HIWORD(wParam) == BN_CLICKED ||
1414 HIWORD(wParam) == BN_DOUBLECLICKED)
1415 cfg.lfhascr = IsDlgButtonChecked (hwnd, IDC2_LFHASCR);
1416 break;
1417 case IDC2_ROWSEDIT:
1418 if (HIWORD(wParam) == EN_CHANGE)
1419 MyGetDlgItemInt (hwnd, IDC2_ROWSEDIT, &cfg.height);
1420 break;
1421 case IDC2_COLSEDIT:
1422 if (HIWORD(wParam) == EN_CHANGE)
1423 MyGetDlgItemInt (hwnd, IDC2_COLSEDIT, &cfg.width);
1424 break;
1425 case IDC2_SAVEEDIT:
1426 if (HIWORD(wParam) == EN_CHANGE)
1427 MyGetDlgItemInt (hwnd, IDC2_SAVEEDIT, &cfg.savelines);
1428 break;
1429 case IDC2_CHOOSEFONT:
1430 lf.lfHeight = cfg.fontheight;
1431 lf.lfWidth = lf.lfEscapement = lf.lfOrientation = 0;
1432 lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = 0;
1433 lf.lfWeight = (cfg.fontisbold ? FW_BOLD : 0);
1434 lf.lfCharSet = cfg.fontcharset;
1435 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
1436 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1437 lf.lfQuality = DEFAULT_QUALITY;
1438 lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
1439 strncpy (lf.lfFaceName, cfg.font, sizeof(lf.lfFaceName)-1);
1440 lf.lfFaceName[sizeof(lf.lfFaceName)-1] = '\0';
1441
1442 cf.lStructSize = sizeof(cf);
1443 cf.hwndOwner = hwnd;
1444 cf.lpLogFont = &lf;
1445 cf.Flags = CF_FIXEDPITCHONLY | CF_FORCEFONTEXIST |
1446 CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
1447
1448 if (ChooseFont (&cf)) {
1449 strncpy (cfg.font, lf.lfFaceName, sizeof(cfg.font)-1);
1450 cfg.font[sizeof(cfg.font)-1] = '\0';
1451 cfg.fontisbold = (lf.lfWeight == FW_BOLD);
1452 cfg.fontcharset = lf.lfCharSet;
1453 cfg.fontheight = lf.lfHeight;
1454 fmtfont (fontstatic);
1455 SetDlgItemText (hwnd, IDC2_FONTSTATIC, fontstatic);
1456 }
1457 break;
1458 case IDC1_BEEP:
1459 if (HIWORD(wParam) == BN_CLICKED ||
1460 HIWORD(wParam) == BN_DOUBLECLICKED)
1461 cfg.beep = IsDlgButtonChecked (hwnd, IDC1_BEEP);
1462 break;
1463 case IDC2_BLINKTEXT:
1464 if (HIWORD(wParam) == BN_CLICKED ||
1465 HIWORD(wParam) == BN_DOUBLECLICKED)
1466 cfg.blinktext = IsDlgButtonChecked (hwnd, IDC2_BLINKTEXT);
1467 break;
1468 case IDC2_BCE:
1469 if (HIWORD(wParam) == BN_CLICKED ||
1470 HIWORD(wParam) == BN_DOUBLECLICKED)
1471 cfg.bce = IsDlgButtonChecked (hwnd, IDC2_BCE);
1472 break;
1473 }
1474 break;
1475 }
1476 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1477 }
1478
1479 static int CALLBACK WindowProc (HWND hwnd, UINT msg,
1480 WPARAM wParam, LPARAM lParam) {
1481 struct ctlpos cp;
1482 switch (msg) {
1483 case WM_INITDIALOG:
1484 /* Accelerators used: [aco] bikty */
1485 ctlposinit(&cp, hwnd);
1486 multiedit(&cp,
1487 "Initial window &title:", IDCW_WINTITLE, IDCW_WINEDIT, 100,
1488 NULL);
1489 checkbox(&cp, "Avoid ever using &icon title", IDCW_WINNAME);
1490 checkbox(&cp, "&Blinking cursor", IDCW_BLINKCUR);
1491 checkbox(&cp, "Displa&y scrollbar", IDCW_SCROLLBAR);
1492 checkbox(&cp, "Loc&k Window size", IDCW_LOCKSIZE);
1493
1494 SetDlgItemText (hwnd, IDCW_WINEDIT, cfg.wintitle);
1495 CheckDlgButton (hwnd, IDCW_WINNAME, cfg.win_name_always);
1496 CheckDlgButton (hwnd, IDCW_BLINKCUR, cfg.blink_cur);
1497 CheckDlgButton (hwnd, IDCW_SCROLLBAR, cfg.scrollbar);
1498 CheckDlgButton (hwnd, IDCW_LOCKSIZE, cfg.locksize);
1499 break;
1500 case WM_COMMAND:
1501 switch (LOWORD(wParam)) {
1502 case IDCW_WINNAME:
1503 if (HIWORD(wParam) == BN_CLICKED ||
1504 HIWORD(wParam) == BN_DOUBLECLICKED)
1505 cfg.win_name_always = IsDlgButtonChecked (hwnd, IDCW_WINNAME);
1506 break;
1507 case IDCW_BLINKCUR:
1508 if (HIWORD(wParam) == BN_CLICKED ||
1509 HIWORD(wParam) == BN_DOUBLECLICKED)
1510 cfg.blink_cur = IsDlgButtonChecked (hwnd, IDCW_BLINKCUR);
1511 break;
1512 case IDCW_SCROLLBAR:
1513 if (HIWORD(wParam) == BN_CLICKED ||
1514 HIWORD(wParam) == BN_DOUBLECLICKED)
1515 cfg.scrollbar = IsDlgButtonChecked (hwnd, IDCW_SCROLLBAR);
1516 break;
1517 case IDCW_LOCKSIZE:
1518 if (HIWORD(wParam) == BN_CLICKED ||
1519 HIWORD(wParam) == BN_DOUBLECLICKED)
1520 cfg.locksize = IsDlgButtonChecked (hwnd, IDCW_LOCKSIZE);
1521 break;
1522 case IDCW_WINEDIT:
1523 if (HIWORD(wParam) == EN_CHANGE)
1524 GetDlgItemText (hwnd, IDCW_WINEDIT, cfg.wintitle,
1525 sizeof(cfg.wintitle)-1);
1526 break;
1527 }
1528 break;
1529 }
1530 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1531 }
1532
1533 static int CALLBACK TelnetProc (HWND hwnd, UINT msg,
1534 WPARAM wParam, LPARAM lParam) {
1535 int i;
1536 struct ctlpos cp;
1537
1538 switch (msg) {
1539 case WM_INITDIALOG:
1540 /* Accelerators used: [aco] bdflrstuv */
1541 ctlposinit(&cp, hwnd);
1542 staticedit(&cp, "Terminal-&type string", IDC3_TTSTATIC, IDC3_TTEDIT);
1543 staticedit(&cp, "Terminal-&speed string", IDC3_TSSTATIC, IDC3_TSEDIT);
1544 staticedit(&cp, "Auto-login &username", IDC3_LOGSTATIC, IDC3_LOGEDIT);
1545 envsetter(&cp, "Environment variables:", IDC3_ENVSTATIC,
1546 "&Variable", IDC3_VARSTATIC, IDC3_VAREDIT,
1547 "Va&lue", IDC3_VALSTATIC, IDC3_VALEDIT,
1548 IDC3_ENVLIST,
1549 "A&dd", IDC3_ENVADD, "&Remove", IDC3_ENVREMOVE);
1550 radioline(&cp, "Handling of OLD_ENVIRON ambiguity:", IDC3_EMSTATIC, 2,
1551 "&BSD (commonplace)", IDC3_EMBSD,
1552 "R&FC 1408 (unusual)", IDC3_EMRFC, NULL);
1553
1554 SetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype);
1555 SetDlgItemText (hwnd, IDC3_TSEDIT, cfg.termspeed);
1556 SetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username);
1557 {
1558 char *p = cfg.environmt;
1559 while (*p) {
1560 SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_ADDSTRING, 0,
1561 (LPARAM) p);
1562 p += strlen(p)+1;
1563 }
1564 }
1565 CheckRadioButton (hwnd, IDC3_EMBSD, IDC3_EMRFC,
1566 cfg.rfc_environ ? IDC3_EMRFC : IDC3_EMBSD);
1567 break;
1568 case WM_COMMAND:
1569 switch (LOWORD(wParam)) {
1570 case IDC3_TTEDIT:
1571 if (HIWORD(wParam) == EN_CHANGE)
1572 GetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype,
1573 sizeof(cfg.termtype)-1);
1574 break;
1575 case IDC3_TSEDIT:
1576 if (HIWORD(wParam) == EN_CHANGE)
1577 GetDlgItemText (hwnd, IDC3_TSEDIT, cfg.termspeed,
1578 sizeof(cfg.termspeed)-1);
1579 break;
1580 case IDC3_LOGEDIT:
1581 if (HIWORD(wParam) == EN_CHANGE)
1582 GetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username,
1583 sizeof(cfg.username)-1);
1584 break;
1585 case IDC3_EMBSD:
1586 case IDC3_EMRFC:
1587 cfg.rfc_environ = IsDlgButtonChecked (hwnd, IDC3_EMRFC);
1588 break;
1589 case IDC3_ENVADD:
1590 if (HIWORD(wParam) == BN_CLICKED ||
1591 HIWORD(wParam) == BN_DOUBLECLICKED) {
1592 char str[sizeof(cfg.environmt)];
1593 char *p;
1594 GetDlgItemText (hwnd, IDC3_VAREDIT, str, sizeof(str)-1);
1595 if (!*str) {
1596 MessageBeep(0);
1597 break;
1598 }
1599 p = str + strlen(str);
1600 *p++ = '\t';
1601 GetDlgItemText (hwnd, IDC3_VALEDIT, p, sizeof(str)-1-(p-str));
1602 if (!*p) {
1603 MessageBeep(0);
1604 break;
1605 }
1606 p = cfg.environmt;
1607 while (*p) {
1608 while (*p) p++;
1609 p++;
1610 }
1611 if ((p-cfg.environmt) + strlen(str) + 2 < sizeof(cfg.environmt)) {
1612 strcpy (p, str);
1613 p[strlen(str)+1] = '\0';
1614 SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_ADDSTRING,
1615 0, (LPARAM)str);
1616 SetDlgItemText (hwnd, IDC3_VAREDIT, "");
1617 SetDlgItemText (hwnd, IDC3_VALEDIT, "");
1618 } else {
1619 MessageBox(hwnd, "Environment too big", "PuTTY Error",
1620 MB_OK | MB_ICONERROR);
1621 }
1622 }
1623 break;
1624 case IDC3_ENVREMOVE:
1625 if (HIWORD(wParam) != BN_CLICKED &&
1626 HIWORD(wParam) != BN_DOUBLECLICKED)
1627 break;
1628 i = SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_GETCURSEL, 0, 0);
1629 if (i == LB_ERR)
1630 MessageBeep (0);
1631 else {
1632 char *p, *q;
1633
1634 SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_DELETESTRING,
1635 i, 0);
1636 p = cfg.environmt;
1637 while (i > 0) {
1638 if (!*p)
1639 goto disaster;
1640 while (*p) p++;
1641 p++;
1642 i--;
1643 }
1644 q = p;
1645 if (!*p)
1646 goto disaster;
1647 while (*p) p++;
1648 p++;
1649 while (*p) {
1650 while (*p)
1651 *q++ = *p++;
1652 *q++ = *p++;
1653 }
1654 *q = '\0';
1655 disaster:;
1656 }
1657 break;
1658 }
1659 break;
1660 }
1661 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1662 }
1663
1664 static int CALLBACK SshProc (HWND hwnd, UINT msg,
1665 WPARAM wParam, LPARAM lParam) {
1666 struct ctlpos cp;
1667 OPENFILENAME of;
1668 char filename[sizeof(cfg.keyfile)];
1669
1670 switch (msg) {
1671 case WM_INITDIALOG:
1672 /* Accelerators used: [aco] 123abdkmprtuw */
1673 ctlposinit(&cp, hwnd);
1674 staticedit(&cp, "Terminal-&type string", IDC3_TTSTATIC, IDC3_TTEDIT);
1675 staticedit(&cp, "Auto-login &username", IDC3_LOGSTATIC, IDC3_LOGEDIT);
1676 multiedit(&cp,
1677 "&Remote command:", IDC3_CMDSTATIC, IDC3_CMDEDIT, 100,
1678 NULL);
1679 checkbox(&cp, "Don't allocate a &pseudo-terminal", IDC3_NOPTY);
1680 checkbox(&cp, "Atte&mpt TIS or CryptoCard authentication",
1681 IDC3_AUTHTIS);
1682 checkbox(&cp, "Allow &agent forwarding", IDC3_AGENTFWD);
1683 editbutton(&cp, "Private &key file for authentication:",
1684 IDC3_PKSTATIC, IDC3_PKEDIT, "Bro&wse...", IDC3_PKBUTTON);
1685 radioline(&cp, "Preferred SSH protocol version:",
1686 IDC3_SSHPROTSTATIC, 2,
1687 "&1", IDC3_SSHPROT1, "&2", IDC3_SSHPROT2, NULL);
1688 radioline(&cp, "Preferred encryption algorithm:", IDC3_CIPHERSTATIC, 3,
1689 "&3DES", IDC3_CIPHER3DES,
1690 "&Blowfish", IDC3_CIPHERBLOWF,
1691 "&DES", IDC3_CIPHERDES, NULL);
1692
1693 SetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype);
1694 SetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username);
1695 CheckDlgButton (hwnd, IDC3_NOPTY, cfg.nopty);
1696 CheckDlgButton (hwnd, IDC3_AGENTFWD, cfg.agentfwd);
1697 CheckRadioButton (hwnd, IDC3_CIPHER3DES, IDC3_CIPHERDES,
1698 cfg.cipher == CIPHER_BLOWFISH ? IDC3_CIPHERBLOWF :
1699 cfg.cipher == CIPHER_DES ? IDC3_CIPHERDES :
1700 IDC3_CIPHER3DES);
1701 CheckRadioButton (hwnd, IDC3_SSHPROT1, IDC3_SSHPROT2,
1702 cfg.sshprot == 1 ? IDC3_SSHPROT1 : IDC3_SSHPROT2);
1703 CheckDlgButton (hwnd, IDC3_AUTHTIS, cfg.try_tis_auth);
1704 SetDlgItemText (hwnd, IDC3_PKEDIT, cfg.keyfile);
1705 SetDlgItemText (hwnd, IDC3_CMDEDIT, cfg.remote_cmd);
1706 break;
1707 case WM_COMMAND:
1708 switch (LOWORD(wParam)) {
1709 case IDC3_TTEDIT:
1710 if (HIWORD(wParam) == EN_CHANGE)
1711 GetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype,
1712 sizeof(cfg.termtype)-1);
1713 break;
1714 case IDC3_LOGEDIT:
1715 if (HIWORD(wParam) == EN_CHANGE)
1716 GetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username,
1717 sizeof(cfg.username)-1);
1718 break;
1719 case IDC3_NOPTY:
1720 if (HIWORD(wParam) == BN_CLICKED ||
1721 HIWORD(wParam) == BN_DOUBLECLICKED)
1722 cfg.nopty = IsDlgButtonChecked (hwnd, IDC3_NOPTY);
1723 break;
1724 case IDC3_AGENTFWD:
1725 if (HIWORD(wParam) == BN_CLICKED ||
1726 HIWORD(wParam) == BN_DOUBLECLICKED)
1727 cfg.agentfwd = IsDlgButtonChecked (hwnd, IDC3_AGENTFWD);
1728 break;
1729 case IDC3_CIPHER3DES:
1730 case IDC3_CIPHERBLOWF:
1731 case IDC3_CIPHERDES:
1732 if (HIWORD(wParam) == BN_CLICKED ||
1733 HIWORD(wParam) == BN_DOUBLECLICKED) {
1734 if (IsDlgButtonChecked (hwnd, IDC3_CIPHER3DES))
1735 cfg.cipher = CIPHER_3DES;
1736 else if (IsDlgButtonChecked (hwnd, IDC3_CIPHERBLOWF))
1737 cfg.cipher = CIPHER_BLOWFISH;
1738 else if (IsDlgButtonChecked (hwnd, IDC3_CIPHERDES))
1739 cfg.cipher = CIPHER_DES;
1740 }
1741 break;
1742 case IDC3_SSHPROT1:
1743 case IDC3_SSHPROT2:
1744 if (HIWORD(wParam) == BN_CLICKED ||
1745 HIWORD(wParam) == BN_DOUBLECLICKED) {
1746 if (IsDlgButtonChecked (hwnd, IDC3_SSHPROT1))
1747 cfg.sshprot = 1;
1748 else if (IsDlgButtonChecked (hwnd, IDC3_SSHPROT2))
1749 cfg.sshprot = 2;
1750 }
1751 break;
1752 case IDC3_AUTHTIS:
1753 if (HIWORD(wParam) == BN_CLICKED ||
1754 HIWORD(wParam) == BN_DOUBLECLICKED)
1755 cfg.try_tis_auth = IsDlgButtonChecked (hwnd, IDC3_AUTHTIS);
1756 break;
1757 case IDC3_PKEDIT:
1758 if (HIWORD(wParam) == EN_CHANGE)
1759 GetDlgItemText (hwnd, IDC3_PKEDIT, cfg.keyfile,
1760 sizeof(cfg.keyfile)-1);
1761 break;
1762 case IDC3_CMDEDIT:
1763 if (HIWORD(wParam) == EN_CHANGE)
1764 GetDlgItemText (hwnd, IDC3_CMDEDIT, cfg.remote_cmd,
1765 sizeof(cfg.remote_cmd)-1);
1766 break;
1767 case IDC3_PKBUTTON:
1768 /*
1769 * FIXME: this crashes. Find out why.
1770 */
1771 memset(&of, 0, sizeof(of));
1772 #ifdef OPENFILENAME_SIZE_VERSION_400
1773 of.lStructSize = OPENFILENAME_SIZE_VERSION_400;
1774 #else
1775 of.lStructSize = sizeof(of);
1776 #endif
1777 of.hwndOwner = hwnd;
1778 of.lpstrFilter = "All Files\0*\0\0\0";
1779 of.lpstrCustomFilter = NULL;
1780 of.nFilterIndex = 1;
1781 of.lpstrFile = filename; strcpy(filename, cfg.keyfile);
1782 of.nMaxFile = sizeof(filename);
1783 of.lpstrFileTitle = NULL;
1784 of.lpstrInitialDir = NULL;
1785 of.lpstrTitle = "Select Public Key File";
1786 of.Flags = 0;
1787 if (GetOpenFileName(&of)) {
1788 strcpy(cfg.keyfile, filename);
1789 SetDlgItemText (hwnd, IDC3_PKEDIT, cfg.keyfile);
1790 }
1791 break;
1792 }
1793 break;
1794 }
1795 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1796 }
1797
1798 static int CALLBACK SelectionProc (HWND hwnd, UINT msg,
1799 WPARAM wParam, LPARAM lParam) {
1800 struct ctlpos cp;
1801 int i;
1802
1803 switch (msg) {
1804 case WM_INITDIALOG:
1805 /* Accelerators used: [aco] stwx */
1806 ctlposinit(&cp, hwnd);
1807 radiobig(&cp, "Action of mouse buttons:", IDC4_MBSTATIC,
1808 "&Windows (Right pastes, Middle extends)", IDC4_MBWINDOWS,
1809 "&xterm (Right extends, Middle pastes)", IDC4_MBXTERM,
1810 NULL);
1811 charclass(&cp, "Character classes:", IDC4_CCSTATIC, IDC4_CCLIST,
1812 "&Set", IDC4_CCSET, IDC4_CCEDIT,
1813 "&to class", IDC4_CCSTATIC2);
1814
1815 CheckRadioButton (hwnd, IDC4_MBWINDOWS, IDC4_MBXTERM,
1816 cfg.mouse_is_xterm ? IDC4_MBXTERM : IDC4_MBWINDOWS);
1817 {
1818 static int tabs[4] = {25, 61, 96, 128};
1819 SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_SETTABSTOPS, 4,
1820 (LPARAM) tabs);
1821 }
1822 for (i=0; i<256; i++) {
1823 char str[100];
1824 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
1825 (i>=0x21 && i != 0x7F) ? i : ' ',
1826 cfg.wordness[i]);
1827 SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_ADDSTRING, 0,
1828 (LPARAM) str);
1829 }
1830 break;
1831 case WM_COMMAND:
1832 switch (LOWORD(wParam)) {
1833 case IDC4_MBWINDOWS:
1834 case IDC4_MBXTERM:
1835 cfg.mouse_is_xterm = IsDlgButtonChecked (hwnd, IDC4_MBXTERM);
1836 break;
1837 case IDC4_CCSET:
1838 {
1839 BOOL ok;
1840 int i;
1841 int n = GetDlgItemInt (hwnd, IDC4_CCEDIT, &ok, FALSE);
1842
1843 if (!ok)
1844 MessageBeep (0);
1845 else {
1846 for (i=0; i<256; i++)
1847 if (SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_GETSEL,
1848 i, 0)) {
1849 char str[100];
1850 cfg.wordness[i] = n;
1851 SendDlgItemMessage (hwnd, IDC4_CCLIST,
1852 LB_DELETESTRING, i, 0);
1853 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
1854 (i>=0x21 && i != 0x7F) ? i : ' ',
1855 cfg.wordness[i]);
1856 SendDlgItemMessage (hwnd, IDC4_CCLIST,
1857 LB_INSERTSTRING, i,
1858 (LPARAM)str);
1859 }
1860 }
1861 }
1862 break;
1863 }
1864 break;
1865 }
1866 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1867 }
1868
1869 static int CALLBACK ColourProc (HWND hwnd, UINT msg,
1870 WPARAM wParam, LPARAM lParam) {
1871 static const char *const colours[] = {
1872 "Default Foreground", "Default Bold Foreground",
1873 "Default Background", "Default Bold Background",
1874 "Cursor Text", "Cursor Colour",
1875 "ANSI Black", "ANSI Black Bold",
1876 "ANSI Red", "ANSI Red Bold",
1877 "ANSI Green", "ANSI Green Bold",
1878 "ANSI Yellow", "ANSI Yellow Bold",
1879 "ANSI Blue", "ANSI Blue Bold",
1880 "ANSI Magenta", "ANSI Magenta Bold",
1881 "ANSI Cyan", "ANSI Cyan Bold",
1882 "ANSI White", "ANSI White Bold"
1883 };
1884 static const int permanent[] = {
1885 TRUE, FALSE, TRUE, FALSE, TRUE, TRUE,
1886 TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE,
1887 TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE
1888 };
1889 struct ctlpos cp;
1890
1891 switch (msg) {
1892 case WM_INITDIALOG:
1893 /* Accelerators used: [aco] bmlu */
1894 ctlposinit(&cp, hwnd);
1895 checkbox(&cp, "&Bolded text is a different colour", IDC5_BOLDCOLOUR);
1896 checkbox(&cp, "Attempt to use &logical palettes", IDC5_PALETTE);
1897 colouredit(&cp, "Select a colo&ur and click to modify it:",
1898 IDC5_STATIC, IDC5_LIST,
1899 "&Modify...", IDC5_CHANGE,
1900 "Red:", IDC5_RSTATIC, IDC5_RVALUE,
1901 "Green:", IDC5_GSTATIC, IDC5_GVALUE,
1902 "Blue:", IDC5_BSTATIC, IDC5_BVALUE, NULL);
1903
1904 CheckDlgButton (hwnd, IDC5_BOLDCOLOUR, cfg.bold_colour);
1905 CheckDlgButton (hwnd, IDC5_PALETTE, cfg.try_palette);
1906 {
1907 int i;
1908 for (i=0; i<22; i++)
1909 if (cfg.bold_colour || permanent[i])
1910 SendDlgItemMessage (hwnd, IDC5_LIST, LB_ADDSTRING, 0,
1911 (LPARAM) colours[i]);
1912 }
1913 SendDlgItemMessage (hwnd, IDC5_LIST, LB_SETCURSEL, 0, 0);
1914 SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[0][0], FALSE);
1915 SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[0][1], FALSE);
1916 SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[0][2], FALSE);
1917 break;
1918 case WM_COMMAND:
1919 switch (LOWORD(wParam)) {
1920 case IDC5_BOLDCOLOUR:
1921 if (HIWORD(wParam) == BN_CLICKED ||
1922 HIWORD(wParam) == BN_DOUBLECLICKED) {
1923 int n, i;
1924 cfg.bold_colour = IsDlgButtonChecked (hwnd, IDC5_BOLDCOLOUR);
1925 n = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCOUNT, 0, 0);
1926 if (cfg.bold_colour && n!=22) {
1927 for (i=0; i<22; i++)
1928 if (!permanent[i])
1929 SendDlgItemMessage (hwnd, IDC5_LIST,
1930 LB_INSERTSTRING, i,
1931 (LPARAM) colours[i]);
1932 } else if (!cfg.bold_colour && n!=12) {
1933 for (i=22; i-- ;)
1934 if (!permanent[i])
1935 SendDlgItemMessage (hwnd, IDC5_LIST,
1936 LB_DELETESTRING, i, 0);
1937 }
1938 }
1939 break;
1940 case IDC5_PALETTE:
1941 if (HIWORD(wParam) == BN_CLICKED ||
1942 HIWORD(wParam) == BN_DOUBLECLICKED)
1943 cfg.try_palette = IsDlgButtonChecked (hwnd, IDC5_PALETTE);
1944 break;
1945 case IDC5_LIST:
1946 if (HIWORD(wParam) == LBN_DBLCLK ||
1947 HIWORD(wParam) == LBN_SELCHANGE) {
1948 int i = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCURSEL,
1949 0, 0);
1950 if (!cfg.bold_colour)
1951 i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
1952 SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[i][0], FALSE);
1953 SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[i][1], FALSE);
1954 SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[i][2], FALSE);
1955 }
1956 break;
1957 case IDC5_CHANGE:
1958 if (HIWORD(wParam) == BN_CLICKED ||
1959 HIWORD(wParam) == BN_DOUBLECLICKED) {
1960 static CHOOSECOLOR cc;
1961 static DWORD custom[16] = {0}; /* zero initialisers */
1962 int i = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCURSEL,
1963 0, 0);
1964 if (!cfg.bold_colour)
1965 i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
1966 cc.lStructSize = sizeof(cc);
1967 cc.hwndOwner = hwnd;
1968 cc.hInstance = (HWND)hinst;
1969 cc.lpCustColors = custom;
1970 cc.rgbResult = RGB (cfg.colours[i][0], cfg.colours[i][1],
1971 cfg.colours[i][2]);
1972 cc.Flags = CC_FULLOPEN | CC_RGBINIT;
1973 if (ChooseColor(&cc)) {
1974 cfg.colours[i][0] =
1975 (unsigned char) (cc.rgbResult & 0xFF);
1976 cfg.colours[i][1] =
1977 (unsigned char) (cc.rgbResult >> 8) & 0xFF;
1978 cfg.colours[i][2] =
1979 (unsigned char) (cc.rgbResult >> 16) & 0xFF;
1980 SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[i][0],
1981 FALSE);
1982 SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[i][1],
1983 FALSE);
1984 SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[i][2],
1985 FALSE);
1986 }
1987 }
1988 break;
1989 }
1990 break;
1991 }
1992 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1993 }
1994
1995 static int CALLBACK TranslationProc (HWND hwnd, UINT msg,
1996 WPARAM wParam, LPARAM lParam) {
1997 struct ctlpos cp;
1998
1999 switch (msg) {
2000 case WM_INITDIALOG:
2001 /* Accelerators used: [aco] beiknpsx */
2002 ctlposinit(&cp, hwnd);
2003 radiobig(&cp,
2004 "Handling of VT100 line drawing characters:", IDC2_VTSTATIC,
2005 "Font has &XWindows encoding", IDC2_VTXWINDOWS,
2006 "Use font in &both ANSI and OEM modes", IDC2_VTOEMANSI,
2007 "Use font in O&EM mode only", IDC2_VTOEMONLY,
2008 "&Poor man's line drawing (""+"", ""-"" and ""|"")",
2009 IDC2_VTPOORMAN, NULL);
2010 radiobig(&cp,
2011 "Character set translation:", IDC6_XLATSTATIC,
2012 "&None", IDC6_NOXLAT,
2013 "&KOI8 / Win-1251", IDC6_KOI8WIN1251,
2014 "&ISO-8859-2 / Win-1250", IDC6_88592WIN1250, NULL);
2015 checkbox(&cp, "CAP&S LOCK acts as cyrillic switch", IDC6_CAPSLOCKCYR);
2016
2017 CheckRadioButton (hwnd, IDC6_NOXLAT, IDC6_88592WIN1250,
2018 cfg.xlat_88592w1250 ? IDC6_88592WIN1250 :
2019 cfg.xlat_enablekoiwin ? IDC6_KOI8WIN1251 :
2020 IDC6_NOXLAT);
2021 CheckDlgButton (hwnd, IDC6_CAPSLOCKCYR, cfg.xlat_capslockcyr);
2022 CheckRadioButton (hwnd, IDC2_VTXWINDOWS, IDC2_VTPOORMAN,
2023 cfg.vtmode == VT_XWINDOWS ? IDC2_VTXWINDOWS :
2024 cfg.vtmode == VT_OEMANSI ? IDC2_VTOEMANSI :
2025 cfg.vtmode == VT_OEMONLY ? IDC2_VTOEMONLY :
2026 IDC2_VTPOORMAN);
2027 case WM_COMMAND:
2028 switch (LOWORD(wParam)) {
2029 case IDC6_NOXLAT:
2030 case IDC6_KOI8WIN1251:
2031 case IDC6_88592WIN1250:
2032 cfg.xlat_enablekoiwin =
2033 IsDlgButtonChecked (hwnd, IDC6_KOI8WIN1251);
2034 cfg.xlat_88592w1250 =
2035 IsDlgButtonChecked (hwnd, IDC6_88592WIN1250);
2036 break;
2037 case IDC6_CAPSLOCKCYR:
2038 if (HIWORD(wParam) == BN_CLICKED ||
2039 HIWORD(wParam) == BN_DOUBLECLICKED) {
2040 cfg.xlat_capslockcyr =
2041 IsDlgButtonChecked (hwnd, IDC6_CAPSLOCKCYR);
2042 }
2043 break;
2044 case IDC2_VTXWINDOWS:
2045 case IDC2_VTOEMANSI:
2046 case IDC2_VTOEMONLY:
2047 case IDC2_VTPOORMAN:
2048 cfg.vtmode =
2049 (IsDlgButtonChecked (hwnd, IDC2_VTXWINDOWS) ? VT_XWINDOWS :
2050 IsDlgButtonChecked (hwnd, IDC2_VTOEMANSI) ? VT_OEMANSI :
2051 IsDlgButtonChecked (hwnd, IDC2_VTOEMONLY) ? VT_OEMONLY :
2052 VT_POORMAN);
2053 break;
2054 }
2055 }
2056 return GeneralPanelProc (hwnd, msg, wParam, lParam);
2057 }
2058
2059 static DLGPROC panelproc[NPANELS] = {
2060 ConnectionProc, KeyboardProc, TerminalProc, WindowProc,
2061 TelnetProc, SshProc, SelectionProc, ColourProc, TranslationProc
2062 };
2063 static char *panelids[NPANELS] = {
2064 MAKEINTRESOURCE(IDD_PANEL0),
2065 MAKEINTRESOURCE(IDD_PANEL1),
2066 MAKEINTRESOURCE(IDD_PANEL2),
2067 MAKEINTRESOURCE(IDD_PANELW),
2068 MAKEINTRESOURCE(IDD_PANEL3),
2069 MAKEINTRESOURCE(IDD_PANEL35),
2070 MAKEINTRESOURCE(IDD_PANEL4),
2071 MAKEINTRESOURCE(IDD_PANEL5),
2072 MAKEINTRESOURCE(IDD_PANEL6)
2073 };
2074
2075 static char *names[NPANELS] = {
2076 "Connection", "Keyboard", "Terminal", "Window", "Telnet",
2077 "SSH", "Selection", "Colours", "Translation"
2078 };
2079
2080 static int mainp[MAIN_NPANELS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8};
2081 static int reconfp[RECONF_NPANELS] = { 1, 2, 3, 6, 7, 8};
2082
2083 static HWND makesubdialog(HWND hwnd, int x, int y, int w, int h, int n) {
2084 RECT r;
2085 HWND ret;
2086 WPARAM font;
2087 r.left = x; r.top = y;
2088 r.right = r.left + w; r.bottom = r.top + h;
2089 MapDialogRect(hwnd, &r);
2090 ret = CreateWindowEx(WS_EX_CONTROLPARENT,
2091 WC_DIALOG, "", /* no title */
2092 WS_CHILD | WS_VISIBLE | DS_SETFONT,
2093 r.left, r.top,
2094 r.right-r.left, r.bottom-r.top,
2095 hwnd, (HMENU)(panelids[n]),
2096 hinst, NULL);
2097 SetWindowLong (ret, DWL_DLGPROC, (LONG)panelproc[n]);
2098 font = SendMessage(hwnd, WM_GETFONT, 0, 0);
2099 SendMessage (ret, WM_SETFONT, font, MAKELPARAM(0, 0));
2100 SendMessage (ret, WM_INITDIALOG, 0, 0);
2101 return ret;
2102 }
2103
2104 static int GenericMainDlgProc (HWND hwnd, UINT msg,
2105 WPARAM wParam, LPARAM lParam,
2106 int npanels, int *panelnums, HWND *page) {
2107 HWND hw, tabctl;
2108
2109 switch (msg) {
2110 case WM_INITDIALOG:
2111 { /* centre the window */
2112 RECT rs, rd;
2113
2114 hw = GetDesktopWindow();
2115 if (GetWindowRect (hw, &rs) && GetWindowRect (hwnd, &rd))
2116 MoveWindow (hwnd, (rs.right + rs.left + rd.left - rd.right)/2,
2117 (rs.bottom + rs.top + rd.top - rd.bottom)/2,
2118 rd.right-rd.left, rd.bottom-rd.top, TRUE);
2119 }
2120 {
2121 RECT r;
2122 r.left = 3; r.right = r.left + 174;
2123 r.top = 3; r.bottom = r.top + 193;
2124 MapDialogRect(hwnd, &r);
2125 tabctl = CreateWindowEx(0, WC_TABCONTROL, "",
2126 WS_CHILD | WS_VISIBLE |
2127 WS_TABSTOP | TCS_MULTILINE,
2128 r.left, r.top,
2129 r.right-r.left, r.bottom-r.top,
2130 hwnd, (HMENU)IDC_TAB, hinst, NULL);
2131
2132 if (!tabctl) {
2133 struct ctlpos cp;
2134 ctlposinit2(&cp, hwnd);
2135 ersatztab(&cp, "Category:", IDC_TABSTATIC1, IDC_TABLIST,
2136 IDC_TABSTATIC2);
2137 } else {
2138 WPARAM font = SendMessage(hwnd, WM_GETFONT, 0, 0);
2139 SendMessage(tabctl, WM_SETFONT, font, MAKELPARAM(TRUE, 0));
2140 }
2141 }
2142 *page = NULL;
2143 if (tabctl) { /* initialise the tab control */
2144 TC_ITEMHEADER tab;
2145 int i;
2146
2147 for (i=0; i<npanels; i++) {
2148 tab.mask = TCIF_TEXT;
2149 tab.pszText = names[panelnums[i]];
2150 TabCtrl_InsertItem (tabctl, i, &tab);
2151 }
2152 } else {
2153 int i;
2154
2155 for (i=0; i<npanels; i++) {
2156 SendDlgItemMessage(hwnd, IDC_TABLIST, CB_ADDSTRING,
2157 0, (LPARAM)names[panelnums[i]]);
2158 }
2159 SendDlgItemMessage(hwnd, IDC_TABLIST, CB_SETCURSEL, 0, 0);
2160 }
2161 *page = makesubdialog(hwnd, 6, 30, 168, 163, panelnums[0]);
2162 SetFocus (*page);
2163 return 0;
2164 case WM_NOTIFY:
2165 if (LOWORD(wParam) == IDC_TAB &&
2166 ((LPNMHDR)lParam)->code == TCN_SELCHANGE) {
2167 int i = TabCtrl_GetCurSel(((LPNMHDR)lParam)->hwndFrom);
2168 if (*page)
2169 DestroyWindow (*page);
2170 *page = makesubdialog(hwnd, 6, 30, 168, 163, panelnums[i]);
2171 SetFocus (((LPNMHDR)lParam)->hwndFrom); /* ensure focus stays */
2172 return 0;
2173 }
2174 break;
2175 case WM_COMMAND:
2176 switch (LOWORD(wParam)) {
2177 case IDC_TABLIST:
2178 if (HIWORD(wParam) == CBN_SELCHANGE) {
2179 HWND tablist = GetDlgItem (hwnd, IDC_TABLIST);
2180 int i = SendMessage (tablist, CB_GETCURSEL, 0, 0);
2181 if (*page)
2182 DestroyWindow (*page);
2183 *page = makesubdialog(hwnd, 6, 30, 168, 163, panelnums[i]);
2184 SetFocus(tablist); /* ensure focus stays */
2185 return 0;
2186 }
2187 break;
2188 case IDOK:
2189 if (*cfg.host)
2190 EndDialog (hwnd, 1);
2191 else
2192 MessageBeep (0);
2193 return 0;
2194 case IDCANCEL:
2195 EndDialog (hwnd, 0);
2196 return 0;
2197 }
2198 return 0;
2199 case WM_CLOSE:
2200 EndDialog (hwnd, 0);
2201 return 0;
2202
2203 /* Grrr Explorer will maximize Dialogs! */
2204 case WM_SIZE:
2205 if (wParam == SIZE_MAXIMIZED)
2206 force_normal(hwnd);
2207 return 0;
2208 }
2209 return 0;
2210 }
2211
2212 static int CALLBACK MainDlgProc (HWND hwnd, UINT msg,
2213 WPARAM wParam, LPARAM lParam) {
2214 #if 0
2215 HWND hw;
2216 int i;
2217 #endif
2218 static HWND page = NULL;
2219
2220 if (msg == WM_COMMAND && LOWORD(wParam) == IDOK) {
2221 #if 0
2222 /*
2223 * If the Connection panel is active and the Session List
2224 * box is selected, we treat a press of Open to have an
2225 * implicit press of Load preceding it.
2226 */
2227 hw = GetDlgItem (hwnd, IDC_TAB);
2228 i = TabCtrl_GetCurSel(hw);
2229 if (panelproc[mainp[i]] == ConnectionProc &&
2230 page && implicit_load_ok) {
2231 SendMessage (page, WM_COMMAND,
2232 MAKELONG(IDC0_SESSLOAD, BN_CLICKED), 0);
2233 }
2234 #endif
2235 }
2236 if (msg == WM_COMMAND && LOWORD(wParam) == IDC_ABOUT) {
2237 EnableWindow(hwnd, 0);
2238 DialogBox(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
2239 GetParent(hwnd), AboutProc);
2240 EnableWindow(hwnd, 1);
2241 SetActiveWindow(hwnd);
2242 }
2243 return GenericMainDlgProc (hwnd, msg, wParam, lParam,
2244 MAIN_NPANELS, mainp, &page);
2245 }
2246
2247 static int CALLBACK ReconfDlgProc (HWND hwnd, UINT msg,
2248 WPARAM wParam, LPARAM lParam) {
2249 static HWND page;
2250 return GenericMainDlgProc (hwnd, msg, wParam, lParam,
2251 RECONF_NPANELS, reconfp, &page);
2252 }
2253
2254 void get_sesslist(int allocate) {
2255 static char otherbuf[2048];
2256 static char *buffer;
2257 int buflen, bufsize, i;
2258 char *p, *ret;
2259 void *handle;
2260
2261 if (allocate) {
2262
2263 if ((handle = enum_settings_start()) == NULL)
2264 return;
2265
2266 buflen = bufsize = 0;
2267 buffer = NULL;
2268 do {
2269 ret = enum_settings_next(handle, otherbuf, sizeof(otherbuf));
2270 if (ret) {
2271 int len = strlen(otherbuf)+1;
2272 if (bufsize < buflen+len) {
2273 bufsize = buflen + len + 2048;
2274 buffer = srealloc(buffer, bufsize);
2275 }
2276 strcpy(buffer+buflen, otherbuf);
2277 buflen += strlen(buffer+buflen)+1;
2278 }
2279 } while (ret);
2280 enum_settings_finish(handle);
2281 buffer = srealloc(buffer, buflen+1);
2282 buffer[buflen] = '\0';
2283
2284 p = buffer;
2285 nsessions = 1; /* "Default Settings" counts as one */
2286 while (*p) {
2287 if (strcmp(p, "Default Settings"))
2288 nsessions++;
2289 while (*p) p++;
2290 p++;
2291 }
2292
2293 sessions = smalloc(nsessions * sizeof(char *));
2294 sessions[0] = "Default Settings";
2295 p = buffer;
2296 i = 1;
2297 while (*p) {
2298 if (strcmp(p, "Default Settings"))
2299 sessions[i++] = p;
2300 while (*p) p++;
2301 p++;
2302 }
2303 } else {
2304 sfree (buffer);
2305 sfree (sessions);
2306 }
2307 }
2308
2309 int do_config (void) {
2310 int ret;
2311
2312 get_sesslist(TRUE);
2313 savedsession[0] = '\0';
2314 ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_MAINBOX), NULL, MainDlgProc);
2315 get_sesslist(FALSE);
2316
2317 return ret;
2318 }
2319
2320 int do_reconfig (HWND hwnd) {
2321 Config backup_cfg;
2322 int ret;
2323
2324 backup_cfg = cfg; /* structure copy */
2325 ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_RECONF), hwnd, ReconfDlgProc);
2326 if (!ret)
2327 cfg = backup_cfg; /* structure copy */
2328 else
2329 force_normal(hwnd);
2330
2331 return ret;
2332 }
2333
2334 void do_defaults (char *session) {
2335 if (session)
2336 load_settings (session, TRUE);
2337 else
2338 load_settings ("Default Settings", FALSE);
2339 }
2340
2341 void logevent (char *string) {
2342 if (nevents >= negsize) {
2343 negsize += 64;
2344 events = srealloc (events, negsize * sizeof(*events));
2345 }
2346 events[nevents] = smalloc(1+strlen(string));
2347 strcpy (events[nevents], string);
2348 nevents++;
2349 if (logbox) {
2350 int count;
2351 SendDlgItemMessage (logbox, IDN_LIST, LB_ADDSTRING,
2352 0, (LPARAM)string);
2353 count = SendDlgItemMessage (logbox, IDN_LIST, LB_GETCOUNT, 0, 0);
2354 SendDlgItemMessage (logbox, IDN_LIST, LB_SETTOPINDEX, count-1, 0);
2355 }
2356 }
2357
2358 void showeventlog (HWND hwnd) {
2359 if (!logbox) {
2360 logbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_LOGBOX),
2361 hwnd, LogProc);
2362 ShowWindow (logbox, SW_SHOWNORMAL);
2363 }
2364 }
2365
2366 void showabout (HWND hwnd) {
2367 if (!abtbox) {
2368 abtbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
2369 hwnd, AboutProc);
2370 ShowWindow (abtbox, SW_SHOWNORMAL);
2371 }
2372 }
2373
2374 void verify_ssh_host_key(char *host, int port, char *keytype,
2375 char *keystr, char *fingerprint) {
2376 int ret;
2377
2378 static const char absentmsg[] =
2379 "The server's host key is not cached in the registry. You\n"
2380 "have no guarantee that the server is the computer you\n"
2381 "think it is.\n"
2382 "The server's key fingerprint is:\n"
2383 "%s\n"
2384 "If you trust this host, hit Yes to add the key to\n"
2385 "PuTTY's cache and carry on connecting.\n"
2386 "If you do not trust this host, hit No to abandon the\n"
2387 "connection.\n";
2388
2389 static const char wrongmsg[] =
2390 "WARNING - POTENTIAL SECURITY BREACH!\n"
2391 "\n"
2392 "The server's host key does not match the one PuTTY has\n"
2393 "cached in the registry. This means that either the\n"
2394 "server administrator has changed the host key, or you\n"
2395 "have actually connected to another computer pretending\n"
2396 "to be the server.\n"
2397 "The new key fingerprint is:\n"
2398 "%s\n"
2399 "If you were expecting this change and trust the new key,\n"
2400 "hit Yes to update PuTTY's cache and continue connecting.\n"
2401 "If you want to carry on connecting but without updating\n"
2402 "the cache, hit No.\n"
2403 "If you want to abandon the connection completely, hit\n"
2404 "Cancel. Hitting Cancel is the ONLY guaranteed safe\n"
2405 "choice.\n";
2406
2407 static const char mbtitle[] = "PuTTY Security Alert";
2408
2409
2410 char message[160+ /* sensible fingerprint max size */
2411 (sizeof(absentmsg) > sizeof(wrongmsg) ?
2412 sizeof(absentmsg) : sizeof(wrongmsg))];
2413
2414 /*
2415 * Verify the key against the registry.
2416 */
2417 ret = verify_host_key(host, port, keytype, keystr);
2418
2419 if (ret == 0) /* success - key matched OK */
2420 return;
2421 if (ret == 2) { /* key was different */
2422 int mbret;
2423 sprintf(message, wrongmsg, fingerprint);
2424 mbret = MessageBox(NULL, message, mbtitle,
2425 MB_ICONWARNING | MB_YESNOCANCEL);
2426 if (mbret == IDYES)
2427 store_host_key(host, port, keytype, keystr);
2428 if (mbret == IDCANCEL)
2429 exit(0);
2430 }
2431 if (ret == 1) { /* key was absent */
2432 int mbret;
2433 sprintf(message, absentmsg, fingerprint);
2434 mbret = MessageBox(NULL, message, mbtitle,
2435 MB_ICONWARNING | MB_YESNO);
2436 if (mbret == IDNO)
2437 exit(0);
2438 store_host_key(host, port, keytype, keystr);
2439 }
2440 }