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