Localise control IDs in each dialog procedure, for maintainability
[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 enum { controlstartvalue = 1000,
1056 IDC_HOSTSTATIC,
1057 IDC_HOST,
1058 IDC_PORTSTATIC,
1059 IDC_PORT,
1060 IDC_PROTSTATIC,
1061 IDC_PROTRAW,
1062 IDC_PROTTELNET,
1063 IDC_PROTSSH,
1064 IDC_SESSSTATIC,
1065 IDC_SESSEDIT,
1066 IDC_SESSLIST,
1067 IDC_SESSLOAD,
1068 IDC_SESSSAVE,
1069 IDC_SESSDEL,
1070 IDC_CLOSEEXIT,
1071 IDC_CLOSEWARN
1072 };
1073
1074 switch (msg) {
1075 case WM_INITDIALOG:
1076 /* Accelerators used: [aco] dehlnprstwx */
1077 ctlposinit(&cp, hwnd);
1078 multiedit(&cp,
1079 "Host &Name", IDC_HOSTSTATIC, IDC_HOST, 75,
1080 "&Port", IDC_PORTSTATIC, IDC_PORT, 25, NULL);
1081 radioline(&cp, "Protocol:", IDC_PROTSTATIC, 3,
1082 "&Raw", IDC_PROTRAW,
1083 "&Telnet", IDC_PROTTELNET,
1084 #ifdef FWHACK
1085 "SS&H/hack",
1086 #else
1087 "SS&H",
1088 #endif
1089 IDC_PROTSSH, NULL);
1090 sesssaver(&cp, "Stor&ed Sessions",
1091 IDC_SESSSTATIC, IDC_SESSEDIT, IDC_SESSLIST,
1092 "&Load", IDC_SESSLOAD,
1093 "&Save", IDC_SESSSAVE,
1094 "&Delete", IDC_SESSDEL, NULL);
1095 checkbox(&cp, "Close Window on E&xit", IDC_CLOSEEXIT);
1096 checkbox(&cp, "&Warn on Close", IDC_CLOSEWARN);
1097
1098 SetDlgItemText (hwnd, IDC_HOST, cfg.host);
1099 SetDlgItemText (hwnd, IDC_SESSEDIT, savedsession);
1100 SetDlgItemInt (hwnd, IDC_PORT, cfg.port, FALSE);
1101 for (i = 0; i < nsessions; i++)
1102 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_ADDSTRING,
1103 0, (LPARAM) (sessions[i]));
1104 CheckRadioButton (hwnd, IDC_PROTRAW, IDC_PROTSSH,
1105 cfg.protocol==PROT_SSH ? IDC_PROTSSH :
1106 cfg.protocol==PROT_TELNET ? IDC_PROTTELNET : IDC_PROTRAW );
1107 CheckDlgButton (hwnd, IDC_CLOSEEXIT, cfg.close_on_exit);
1108 CheckDlgButton (hwnd, IDC_CLOSEWARN, cfg.warn_on_close);
1109 break;
1110 case WM_LBUTTONUP:
1111 /*
1112 * Button release should trigger WM_OK if there was a
1113 * previous double click on the session list.
1114 */
1115 ReleaseCapture();
1116 if (readytogo)
1117 SendMessage (GetParent(hwnd), WM_COMMAND, IDOK, 0);
1118 break;
1119 case WM_COMMAND:
1120 switch (LOWORD(wParam)) {
1121 case IDC_PROTTELNET:
1122 case IDC_PROTSSH:
1123 case IDC_PROTRAW:
1124 if (HIWORD(wParam) == BN_CLICKED ||
1125 HIWORD(wParam) == BN_DOUBLECLICKED) {
1126 int i = IsDlgButtonChecked (hwnd, IDC_PROTSSH);
1127 int j = IsDlgButtonChecked (hwnd, IDC_PROTTELNET);
1128 cfg.protocol = i ? PROT_SSH : j ? PROT_TELNET : PROT_RAW ;
1129 if ((cfg.protocol == PROT_SSH && cfg.port == 23) ||
1130 (cfg.protocol == PROT_TELNET && cfg.port == 22)) {
1131 cfg.port = i ? 22 : 23;
1132 SetDlgItemInt (hwnd, IDC_PORT, cfg.port, FALSE);
1133 }
1134 }
1135 break;
1136 case IDC_HOST:
1137 if (HIWORD(wParam) == EN_CHANGE)
1138 GetDlgItemText (hwnd, IDC_HOST, cfg.host,
1139 sizeof(cfg.host)-1);
1140 break;
1141 case IDC_PORT:
1142 if (HIWORD(wParam) == EN_CHANGE)
1143 MyGetDlgItemInt (hwnd, IDC_PORT, &cfg.port);
1144 break;
1145 case IDC_CLOSEEXIT:
1146 if (HIWORD(wParam) == BN_CLICKED ||
1147 HIWORD(wParam) == BN_DOUBLECLICKED)
1148 cfg.close_on_exit = IsDlgButtonChecked (hwnd, IDC_CLOSEEXIT);
1149 break;
1150 case IDC_CLOSEWARN:
1151 if (HIWORD(wParam) == BN_CLICKED ||
1152 HIWORD(wParam) == BN_DOUBLECLICKED)
1153 cfg.warn_on_close = IsDlgButtonChecked (hwnd, IDC_CLOSEWARN);
1154 break;
1155 case IDC_SESSEDIT:
1156 if (HIWORD(wParam) == EN_CHANGE) {
1157 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL,
1158 (WPARAM) -1, 0);
1159 GetDlgItemText (hwnd, IDC_SESSEDIT,
1160 savedsession, sizeof(savedsession)-1);
1161 savedsession[sizeof(savedsession)-1] = '\0';
1162 }
1163 break;
1164 case IDC_SESSSAVE:
1165 if (HIWORD(wParam) == BN_CLICKED ||
1166 HIWORD(wParam) == BN_DOUBLECLICKED) {
1167 /*
1168 * Save a session
1169 */
1170 char str[2048];
1171 GetDlgItemText (hwnd, IDC_SESSEDIT, str, sizeof(str)-1);
1172 if (!*str) {
1173 int n = SendDlgItemMessage (hwnd, IDC_SESSLIST,
1174 LB_GETCURSEL, 0, 0);
1175 if (n == LB_ERR) {
1176 MessageBeep(0);
1177 break;
1178 }
1179 strcpy (str, sessions[n]);
1180 }
1181 save_settings (str, !!strcmp(str, "Default Settings"));
1182 get_sesslist (FALSE);
1183 get_sesslist (TRUE);
1184 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_RESETCONTENT,
1185 0, 0);
1186 for (i = 0; i < nsessions; i++)
1187 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_ADDSTRING,
1188 0, (LPARAM) (sessions[i]));
1189 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL,
1190 (WPARAM) -1, 0);
1191 }
1192 break;
1193 case IDC_SESSLIST:
1194 case IDC_SESSLOAD:
1195 if (LOWORD(wParam) == IDC_SESSLOAD &&
1196 HIWORD(wParam) != BN_CLICKED &&
1197 HIWORD(wParam) != BN_DOUBLECLICKED)
1198 break;
1199 if (LOWORD(wParam) == IDC_SESSLIST &&
1200 HIWORD(wParam) != LBN_DBLCLK)
1201 break;
1202 {
1203 int n = SendDlgItemMessage (hwnd, IDC_SESSLIST,
1204 LB_GETCURSEL, 0, 0);
1205 if (n == LB_ERR) {
1206 MessageBeep(0);
1207 break;
1208 }
1209 load_settings (sessions[n],
1210 !!strcmp(sessions[n], "Default Settings"));
1211 SetDlgItemText (hwnd, IDC_HOST, cfg.host);
1212 SetDlgItemInt (hwnd, IDC_PORT, cfg.port, FALSE);
1213 CheckRadioButton (hwnd, IDC_PROTRAW, IDC_PROTSSH,
1214 (cfg.protocol==PROT_SSH ? IDC_PROTSSH :
1215 cfg.protocol==PROT_TELNET ? IDC_PROTTELNET : IDC_PROTRAW));
1216 CheckDlgButton (hwnd, IDC_CLOSEEXIT, cfg.close_on_exit);
1217 CheckDlgButton (hwnd, IDC_CLOSEWARN, cfg.warn_on_close);
1218 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL,
1219 (WPARAM) -1, 0);
1220 }
1221 if (LOWORD(wParam) == IDC_SESSLIST) {
1222 /*
1223 * A double-click on a saved session should
1224 * actually start the session, not just load it.
1225 * Unless it's Default Settings or some other
1226 * host-less set of saved settings.
1227 */
1228 if (*cfg.host) {
1229 readytogo = TRUE;
1230 SetCapture(hwnd);
1231 }
1232 }
1233 break;
1234 case IDC_SESSDEL:
1235 if (HIWORD(wParam) == BN_CLICKED ||
1236 HIWORD(wParam) == BN_DOUBLECLICKED) {
1237 int n = SendDlgItemMessage (hwnd, IDC_SESSLIST,
1238 LB_GETCURSEL, 0, 0);
1239 if (n == LB_ERR || n == 0) {
1240 MessageBeep(0);
1241 break;
1242 }
1243 del_settings(sessions[n]);
1244 get_sesslist (FALSE);
1245 get_sesslist (TRUE);
1246 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_RESETCONTENT,
1247 0, 0);
1248 for (i = 0; i < nsessions; i++)
1249 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_ADDSTRING,
1250 0, (LPARAM) (sessions[i]));
1251 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL,
1252 (WPARAM) -1, 0);
1253 }
1254 }
1255 }
1256 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1257 }
1258
1259 static int CALLBACK KeyboardProc (HWND hwnd, UINT msg,
1260 WPARAM wParam, LPARAM lParam) {
1261 struct ctlpos cp;
1262 enum { controlstartvalue = 1000,
1263 IDC_DELSTATIC,
1264 IDC_DEL008,
1265 IDC_DEL127,
1266 IDC_HOMESTATIC,
1267 IDC_HOMETILDE,
1268 IDC_HOMERXVT,
1269 IDC_FUNCSTATIC,
1270 IDC_FUNCTILDE,
1271 IDC_FUNCLINUX,
1272 IDC_FUNCXTERM,
1273 IDC_KPSTATIC,
1274 IDC_KPNORMAL,
1275 IDC_KPAPPLIC,
1276 IDC_KPNH,
1277 IDC_CURSTATIC,
1278 IDC_CURNORMAL,
1279 IDC_CURAPPLIC,
1280 IDC_ALTF4,
1281 IDC_ALTSPACE,
1282 IDC_LDISCTERM,
1283 IDC_SCROLLKEY
1284 };
1285
1286 switch (msg) {
1287 case WM_INITDIALOG:
1288 /* Accelerators used: [aco] 4?ehiklmnprsuvxy */
1289 ctlposinit(&cp, hwnd);
1290 radioline(&cp, "Action of Backspace:", IDC_DELSTATIC, 2,
1291 "Control-&H", IDC_DEL008,
1292 "Control-&? (127)", IDC_DEL127, NULL);
1293 radioline(&cp, "Action of Home and End:", IDC_HOMESTATIC, 2,
1294 "&Standard", IDC_HOMETILDE,
1295 "&rxvt", IDC_HOMERXVT, NULL);
1296 radioline(&cp, "Function key and keypad layout:", IDC_FUNCSTATIC, 3,
1297 "&VT400", IDC_FUNCTILDE,
1298 "&Linux", IDC_FUNCLINUX,
1299 "&Xterm R6", IDC_FUNCXTERM, NULL);
1300 radioline(&cp, "Initial state of cursor keys:", IDC_CURSTATIC, 2,
1301 "&Normal", IDC_CURNORMAL,
1302 "A&pplication", IDC_CURAPPLIC, NULL);
1303 radioline(&cp, "Initial state of numeric keypad:", IDC_KPSTATIC, 3,
1304 "Nor&mal", IDC_KPNORMAL,
1305 "Appl&ication", IDC_KPAPPLIC,
1306 "N&etHack", IDC_KPNH, NULL);
1307 checkbox(&cp, "ALT-F&4 is special (closes window)", IDC_ALTF4);
1308 checkbox(&cp, "ALT-Space is special (S&ystem menu)", IDC_ALTSPACE);
1309 checkbox(&cp, "&Use local terminal line discipline", IDC_LDISCTERM);
1310 checkbox(&cp, "Reset scrollback on &keypress", IDC_SCROLLKEY);
1311
1312 CheckRadioButton (hwnd, IDC_DEL008, IDC_DEL127,
1313 cfg.bksp_is_delete ? IDC_DEL127 : IDC_DEL008);
1314 CheckRadioButton (hwnd, IDC_HOMETILDE, IDC_HOMERXVT,
1315 cfg.rxvt_homeend ? IDC_HOMERXVT : IDC_HOMETILDE);
1316 CheckRadioButton (hwnd, IDC_FUNCTILDE, IDC_FUNCXTERM,
1317 cfg.funky_type ?
1318 (cfg.funky_type==2 ? IDC_FUNCXTERM
1319 : IDC_FUNCLINUX )
1320 : IDC_FUNCTILDE);
1321 CheckRadioButton (hwnd, IDC_CURNORMAL, IDC_CURAPPLIC,
1322 cfg.app_cursor ? IDC_CURAPPLIC : IDC_CURNORMAL);
1323 CheckRadioButton (hwnd, IDC_KPNORMAL, IDC_KPNH,
1324 cfg.nethack_keypad ? IDC_KPNH :
1325 cfg.app_keypad ? IDC_KPAPPLIC : IDC_KPNORMAL);
1326 CheckDlgButton (hwnd, IDC_ALTF4, cfg.alt_f4);
1327 CheckDlgButton (hwnd, IDC_ALTSPACE, cfg.alt_space);
1328 CheckDlgButton (hwnd, IDC_LDISCTERM, cfg.ldisc_term);
1329 CheckDlgButton (hwnd, IDC_SCROLLKEY, cfg.scroll_on_key);
1330 break;
1331 case WM_COMMAND:
1332 if (HIWORD(wParam) == BN_CLICKED ||
1333 HIWORD(wParam) == BN_DOUBLECLICKED)
1334 switch (LOWORD(wParam)) {
1335 case IDC_DEL008:
1336 case IDC_DEL127:
1337 cfg.bksp_is_delete = IsDlgButtonChecked (hwnd, IDC_DEL127);
1338 break;
1339 case IDC_HOMETILDE:
1340 case IDC_HOMERXVT:
1341 cfg.rxvt_homeend = IsDlgButtonChecked (hwnd, IDC_HOMERXVT);
1342 break;
1343 case IDC_FUNCXTERM:
1344 cfg.funky_type = 2;
1345 break;
1346 case IDC_FUNCTILDE:
1347 case IDC_FUNCLINUX:
1348 cfg.funky_type = IsDlgButtonChecked (hwnd, IDC_FUNCLINUX);
1349 break;
1350 case IDC_KPNORMAL:
1351 case IDC_KPAPPLIC:
1352 cfg.app_keypad = IsDlgButtonChecked (hwnd, IDC_KPAPPLIC);
1353 cfg.nethack_keypad = FALSE;
1354 break;
1355 case IDC_KPNH:
1356 cfg.app_keypad = FALSE;
1357 cfg.nethack_keypad = TRUE;
1358 break;
1359 case IDC_CURNORMAL:
1360 case IDC_CURAPPLIC:
1361 cfg.app_cursor = IsDlgButtonChecked (hwnd, IDC_CURAPPLIC);
1362 break;
1363 case IDC_ALTF4:
1364 if (HIWORD(wParam) == BN_CLICKED ||
1365 HIWORD(wParam) == BN_DOUBLECLICKED)
1366 cfg.alt_f4 = IsDlgButtonChecked (hwnd, IDC_ALTF4);
1367 break;
1368 case IDC_ALTSPACE:
1369 if (HIWORD(wParam) == BN_CLICKED ||
1370 HIWORD(wParam) == BN_DOUBLECLICKED)
1371 cfg.alt_space = IsDlgButtonChecked (hwnd, IDC_ALTSPACE);
1372 break;
1373 case IDC_LDISCTERM:
1374 if (HIWORD(wParam) == BN_CLICKED ||
1375 HIWORD(wParam) == BN_DOUBLECLICKED)
1376 cfg.ldisc_term = IsDlgButtonChecked (hwnd, IDC_LDISCTERM);
1377 break;
1378 case IDC_SCROLLKEY:
1379 if (HIWORD(wParam) == BN_CLICKED ||
1380 HIWORD(wParam) == BN_DOUBLECLICKED)
1381 cfg.scroll_on_key = IsDlgButtonChecked (hwnd, IDC_SCROLLKEY);
1382 break;
1383 }
1384 }
1385 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1386 }
1387
1388 static void fmtfont (char *buf) {
1389 sprintf (buf, "Font: %s, ", cfg.font);
1390 if (cfg.fontisbold)
1391 strcat(buf, "bold, ");
1392 if (cfg.fontheight == 0)
1393 strcat (buf, "default height");
1394 else
1395 sprintf (buf+strlen(buf), "%d-%s",
1396 (cfg.fontheight < 0 ? -cfg.fontheight : cfg.fontheight),
1397 (cfg.fontheight < 0 ? "pixel" : "point"));
1398 }
1399
1400 static int CALLBACK TerminalProc (HWND hwnd, UINT msg,
1401 WPARAM wParam, LPARAM lParam) {
1402 struct ctlpos cp;
1403 CHOOSEFONT cf;
1404 LOGFONT lf;
1405 char fontstatic[256];
1406 enum { controlstartvalue = 1000,
1407 IDC_WRAPMODE,
1408 IDC_DECOM,
1409 IDC_DIMSTATIC,
1410 IDC_ROWSSTATIC,
1411 IDC_ROWSEDIT,
1412 IDC_COLSSTATIC,
1413 IDC_COLSEDIT,
1414 IDC_SAVESTATIC,
1415 IDC_SAVEEDIT,
1416 IDC_FONTSTATIC,
1417 IDC_CHOOSEFONT,
1418 IDC_LFHASCR,
1419 IDC_BEEP,
1420 IDC_BCE,
1421 IDC_BLINKTEXT
1422 };
1423
1424 switch (msg) {
1425 case WM_INITDIALOG:
1426 /* Accelerators used: [aco] dghlmnprsw */
1427 ctlposinit(&cp, hwnd);
1428 multiedit(&cp,
1429 "&Rows", IDC_ROWSSTATIC, IDC_ROWSEDIT, 33,
1430 "Colu&mns", IDC_COLSSTATIC, IDC_COLSEDIT, 33,
1431 "&Scrollback", IDC_SAVESTATIC, IDC_SAVEEDIT, 33,
1432 NULL);
1433 staticbtn(&cp, "", IDC_FONTSTATIC, "C&hange...", IDC_CHOOSEFONT);
1434 checkbox(&cp, "Auto &wrap mode initially on", IDC_WRAPMODE);
1435 checkbox(&cp, "&DEC Origin Mode initially on", IDC_DECOM);
1436 checkbox(&cp, "Implicit CR in every &LF", IDC_LFHASCR);
1437 checkbox(&cp, "Bee&p enabled", IDC_BEEP);
1438 checkbox(&cp, "Use Back&ground colour erase", IDC_BCE);
1439 checkbox(&cp, "Enable bli&nking text", IDC_BLINKTEXT);
1440
1441 CheckDlgButton (hwnd, IDC_WRAPMODE, cfg.wrap_mode);
1442 CheckDlgButton (hwnd, IDC_DECOM, cfg.dec_om);
1443 CheckDlgButton (hwnd, IDC_LFHASCR, cfg.lfhascr);
1444 SetDlgItemInt (hwnd, IDC_ROWSEDIT, cfg.height, FALSE);
1445 SetDlgItemInt (hwnd, IDC_COLSEDIT, cfg.width, FALSE);
1446 SetDlgItemInt (hwnd, IDC_SAVEEDIT, cfg.savelines, FALSE);
1447 fmtfont (fontstatic);
1448 SetDlgItemText (hwnd, IDC_FONTSTATIC, fontstatic);
1449 CheckDlgButton (hwnd, IDC_BEEP, cfg.beep);
1450 CheckDlgButton (hwnd, IDC_BCE, cfg.bce);
1451 CheckDlgButton (hwnd, IDC_BLINKTEXT, cfg.blinktext);
1452 break;
1453 case WM_COMMAND:
1454 switch (LOWORD(wParam)) {
1455 case IDC_WRAPMODE:
1456 if (HIWORD(wParam) == BN_CLICKED ||
1457 HIWORD(wParam) == BN_DOUBLECLICKED)
1458 cfg.wrap_mode = IsDlgButtonChecked (hwnd, IDC_WRAPMODE);
1459 break;
1460 case IDC_DECOM:
1461 if (HIWORD(wParam) == BN_CLICKED ||
1462 HIWORD(wParam) == BN_DOUBLECLICKED)
1463 cfg.dec_om = IsDlgButtonChecked (hwnd, IDC_DECOM);
1464 break;
1465 case IDC_LFHASCR:
1466 if (HIWORD(wParam) == BN_CLICKED ||
1467 HIWORD(wParam) == BN_DOUBLECLICKED)
1468 cfg.lfhascr = IsDlgButtonChecked (hwnd, IDC_LFHASCR);
1469 break;
1470 case IDC_ROWSEDIT:
1471 if (HIWORD(wParam) == EN_CHANGE)
1472 MyGetDlgItemInt (hwnd, IDC_ROWSEDIT, &cfg.height);
1473 break;
1474 case IDC_COLSEDIT:
1475 if (HIWORD(wParam) == EN_CHANGE)
1476 MyGetDlgItemInt (hwnd, IDC_COLSEDIT, &cfg.width);
1477 break;
1478 case IDC_SAVEEDIT:
1479 if (HIWORD(wParam) == EN_CHANGE)
1480 MyGetDlgItemInt (hwnd, IDC_SAVEEDIT, &cfg.savelines);
1481 break;
1482 case IDC_CHOOSEFONT:
1483 lf.lfHeight = cfg.fontheight;
1484 lf.lfWidth = lf.lfEscapement = lf.lfOrientation = 0;
1485 lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = 0;
1486 lf.lfWeight = (cfg.fontisbold ? FW_BOLD : 0);
1487 lf.lfCharSet = cfg.fontcharset;
1488 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
1489 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1490 lf.lfQuality = DEFAULT_QUALITY;
1491 lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
1492 strncpy (lf.lfFaceName, cfg.font, sizeof(lf.lfFaceName)-1);
1493 lf.lfFaceName[sizeof(lf.lfFaceName)-1] = '\0';
1494
1495 cf.lStructSize = sizeof(cf);
1496 cf.hwndOwner = hwnd;
1497 cf.lpLogFont = &lf;
1498 cf.Flags = CF_FIXEDPITCHONLY | CF_FORCEFONTEXIST |
1499 CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
1500
1501 if (ChooseFont (&cf)) {
1502 strncpy (cfg.font, lf.lfFaceName, sizeof(cfg.font)-1);
1503 cfg.font[sizeof(cfg.font)-1] = '\0';
1504 cfg.fontisbold = (lf.lfWeight == FW_BOLD);
1505 cfg.fontcharset = lf.lfCharSet;
1506 cfg.fontheight = lf.lfHeight;
1507 fmtfont (fontstatic);
1508 SetDlgItemText (hwnd, IDC_FONTSTATIC, fontstatic);
1509 }
1510 break;
1511 case IDC_BEEP:
1512 if (HIWORD(wParam) == BN_CLICKED ||
1513 HIWORD(wParam) == BN_DOUBLECLICKED)
1514 cfg.beep = IsDlgButtonChecked (hwnd, IDC_BEEP);
1515 break;
1516 case IDC_BLINKTEXT:
1517 if (HIWORD(wParam) == BN_CLICKED ||
1518 HIWORD(wParam) == BN_DOUBLECLICKED)
1519 cfg.blinktext = IsDlgButtonChecked (hwnd, IDC_BLINKTEXT);
1520 break;
1521 case IDC_BCE:
1522 if (HIWORD(wParam) == BN_CLICKED ||
1523 HIWORD(wParam) == BN_DOUBLECLICKED)
1524 cfg.bce = IsDlgButtonChecked (hwnd, IDC_BCE);
1525 break;
1526 }
1527 break;
1528 }
1529 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1530 }
1531
1532 static int CALLBACK WindowProc (HWND hwnd, UINT msg,
1533 WPARAM wParam, LPARAM lParam) {
1534 struct ctlpos cp;
1535 enum { controlstartvalue = 1000,
1536 IDC_WINNAME,
1537 IDC_BLINKCUR,
1538 IDC_SCROLLBAR,
1539 IDC_LOCKSIZE,
1540 IDC_WINTITLE,
1541 IDC_WINEDIT
1542 };
1543
1544 switch (msg) {
1545 case WM_INITDIALOG:
1546 /* Accelerators used: [aco] bikty */
1547 ctlposinit(&cp, hwnd);
1548 multiedit(&cp,
1549 "Initial window &title:", IDC_WINTITLE, IDC_WINEDIT, 100,
1550 NULL);
1551 checkbox(&cp, "Avoid ever using &icon title", IDC_WINNAME);
1552 checkbox(&cp, "&Blinking cursor", IDC_BLINKCUR);
1553 checkbox(&cp, "Displa&y scrollbar", IDC_SCROLLBAR);
1554 checkbox(&cp, "Loc&k Window size", IDC_LOCKSIZE);
1555
1556 SetDlgItemText (hwnd, IDC_WINEDIT, cfg.wintitle);
1557 CheckDlgButton (hwnd, IDC_WINNAME, cfg.win_name_always);
1558 CheckDlgButton (hwnd, IDC_BLINKCUR, cfg.blink_cur);
1559 CheckDlgButton (hwnd, IDC_SCROLLBAR, cfg.scrollbar);
1560 CheckDlgButton (hwnd, IDC_LOCKSIZE, cfg.locksize);
1561 break;
1562 case WM_COMMAND:
1563 switch (LOWORD(wParam)) {
1564 case IDC_WINNAME:
1565 if (HIWORD(wParam) == BN_CLICKED ||
1566 HIWORD(wParam) == BN_DOUBLECLICKED)
1567 cfg.win_name_always = IsDlgButtonChecked (hwnd, IDC_WINNAME);
1568 break;
1569 case IDC_BLINKCUR:
1570 if (HIWORD(wParam) == BN_CLICKED ||
1571 HIWORD(wParam) == BN_DOUBLECLICKED)
1572 cfg.blink_cur = IsDlgButtonChecked (hwnd, IDC_BLINKCUR);
1573 break;
1574 case IDC_SCROLLBAR:
1575 if (HIWORD(wParam) == BN_CLICKED ||
1576 HIWORD(wParam) == BN_DOUBLECLICKED)
1577 cfg.scrollbar = IsDlgButtonChecked (hwnd, IDC_SCROLLBAR);
1578 break;
1579 case IDC_LOCKSIZE:
1580 if (HIWORD(wParam) == BN_CLICKED ||
1581 HIWORD(wParam) == BN_DOUBLECLICKED)
1582 cfg.locksize = IsDlgButtonChecked (hwnd, IDC_LOCKSIZE);
1583 break;
1584 case IDC_WINEDIT:
1585 if (HIWORD(wParam) == EN_CHANGE)
1586 GetDlgItemText (hwnd, IDC_WINEDIT, cfg.wintitle,
1587 sizeof(cfg.wintitle)-1);
1588 break;
1589 }
1590 break;
1591 }
1592 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1593 }
1594
1595 static int CALLBACK TelnetProc (HWND hwnd, UINT msg,
1596 WPARAM wParam, LPARAM lParam) {
1597 int i;
1598 struct ctlpos cp;
1599 enum { controlstartvalue = 1000,
1600 IDC_TTSTATIC,
1601 IDC_TTEDIT,
1602 IDC_TSSTATIC,
1603 IDC_TSEDIT,
1604 IDC_LOGSTATIC,
1605 IDC_LOGEDIT,
1606 IDC_ENVSTATIC,
1607 IDC_VARSTATIC,
1608 IDC_VAREDIT,
1609 IDC_VALSTATIC,
1610 IDC_VALEDIT,
1611 IDC_ENVLIST,
1612 IDC_ENVADD,
1613 IDC_ENVREMOVE,
1614 IDC_EMSTATIC,
1615 IDC_EMBSD,
1616 IDC_EMRFC
1617 };
1618
1619 switch (msg) {
1620 case WM_INITDIALOG:
1621 /* Accelerators used: [aco] bdflrstuv */
1622 ctlposinit(&cp, hwnd);
1623 staticedit(&cp, "Terminal-&type string", IDC_TTSTATIC, IDC_TTEDIT);
1624 staticedit(&cp, "Terminal-&speed string", IDC_TSSTATIC, IDC_TSEDIT);
1625 staticedit(&cp, "Auto-login &username", IDC_LOGSTATIC, IDC_LOGEDIT);
1626 envsetter(&cp, "Environment variables:", IDC_ENVSTATIC,
1627 "&Variable", IDC_VARSTATIC, IDC_VAREDIT,
1628 "Va&lue", IDC_VALSTATIC, IDC_VALEDIT,
1629 IDC_ENVLIST,
1630 "A&dd", IDC_ENVADD, "&Remove", IDC_ENVREMOVE);
1631 radioline(&cp, "Handling of OLD_ENVIRON ambiguity:", IDC_EMSTATIC, 2,
1632 "&BSD (commonplace)", IDC_EMBSD,
1633 "R&FC 1408 (unusual)", IDC_EMRFC, NULL);
1634
1635 SetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype);
1636 SetDlgItemText (hwnd, IDC_TSEDIT, cfg.termspeed);
1637 SetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username);
1638 {
1639 char *p = cfg.environmt;
1640 while (*p) {
1641 SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_ADDSTRING, 0,
1642 (LPARAM) p);
1643 p += strlen(p)+1;
1644 }
1645 }
1646 CheckRadioButton (hwnd, IDC_EMBSD, IDC_EMRFC,
1647 cfg.rfc_environ ? IDC_EMRFC : IDC_EMBSD);
1648 break;
1649 case WM_COMMAND:
1650 switch (LOWORD(wParam)) {
1651 case IDC_TTEDIT:
1652 if (HIWORD(wParam) == EN_CHANGE)
1653 GetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype,
1654 sizeof(cfg.termtype)-1);
1655 break;
1656 case IDC_TSEDIT:
1657 if (HIWORD(wParam) == EN_CHANGE)
1658 GetDlgItemText (hwnd, IDC_TSEDIT, cfg.termspeed,
1659 sizeof(cfg.termspeed)-1);
1660 break;
1661 case IDC_LOGEDIT:
1662 if (HIWORD(wParam) == EN_CHANGE)
1663 GetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username,
1664 sizeof(cfg.username)-1);
1665 break;
1666 case IDC_EMBSD:
1667 case IDC_EMRFC:
1668 cfg.rfc_environ = IsDlgButtonChecked (hwnd, IDC_EMRFC);
1669 break;
1670 case IDC_ENVADD:
1671 if (HIWORD(wParam) == BN_CLICKED ||
1672 HIWORD(wParam) == BN_DOUBLECLICKED) {
1673 char str[sizeof(cfg.environmt)];
1674 char *p;
1675 GetDlgItemText (hwnd, IDC_VAREDIT, str, sizeof(str)-1);
1676 if (!*str) {
1677 MessageBeep(0);
1678 break;
1679 }
1680 p = str + strlen(str);
1681 *p++ = '\t';
1682 GetDlgItemText (hwnd, IDC_VALEDIT, p, sizeof(str)-1-(p-str));
1683 if (!*p) {
1684 MessageBeep(0);
1685 break;
1686 }
1687 p = cfg.environmt;
1688 while (*p) {
1689 while (*p) p++;
1690 p++;
1691 }
1692 if ((p-cfg.environmt) + strlen(str) + 2 < sizeof(cfg.environmt)) {
1693 strcpy (p, str);
1694 p[strlen(str)+1] = '\0';
1695 SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_ADDSTRING,
1696 0, (LPARAM)str);
1697 SetDlgItemText (hwnd, IDC_VAREDIT, "");
1698 SetDlgItemText (hwnd, IDC_VALEDIT, "");
1699 } else {
1700 MessageBox(hwnd, "Environment too big", "PuTTY Error",
1701 MB_OK | MB_ICONERROR);
1702 }
1703 }
1704 break;
1705 case IDC_ENVREMOVE:
1706 if (HIWORD(wParam) != BN_CLICKED &&
1707 HIWORD(wParam) != BN_DOUBLECLICKED)
1708 break;
1709 i = SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_GETCURSEL, 0, 0);
1710 if (i == LB_ERR)
1711 MessageBeep (0);
1712 else {
1713 char *p, *q;
1714
1715 SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_DELETESTRING,
1716 i, 0);
1717 p = cfg.environmt;
1718 while (i > 0) {
1719 if (!*p)
1720 goto disaster;
1721 while (*p) p++;
1722 p++;
1723 i--;
1724 }
1725 q = p;
1726 if (!*p)
1727 goto disaster;
1728 while (*p) p++;
1729 p++;
1730 while (*p) {
1731 while (*p)
1732 *q++ = *p++;
1733 *q++ = *p++;
1734 }
1735 *q = '\0';
1736 disaster:;
1737 }
1738 break;
1739 }
1740 break;
1741 }
1742 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1743 }
1744
1745 static int CALLBACK SshProc (HWND hwnd, UINT msg,
1746 WPARAM wParam, LPARAM lParam) {
1747 struct ctlpos cp;
1748 OPENFILENAME of;
1749 char filename[sizeof(cfg.keyfile)];
1750 enum { controlstartvalue = 1000,
1751 IDC_TTSTATIC,
1752 IDC_TTEDIT,
1753 IDC_LOGSTATIC,
1754 IDC_LOGEDIT,
1755 IDC_NOPTY,
1756 IDC_CIPHERSTATIC,
1757 IDC_CIPHER3DES,
1758 IDC_CIPHERBLOWF,
1759 IDC_CIPHERDES,
1760 IDC_AUTHTIS,
1761 IDC_PKSTATIC,
1762 IDC_PKEDIT,
1763 IDC_PKBUTTON,
1764 IDC_SSHPROTSTATIC,
1765 IDC_SSHPROT1,
1766 IDC_SSHPROT2,
1767 IDC_AGENTFWD,
1768 IDC_CMDSTATIC,
1769 IDC_CMDEDIT
1770 };
1771
1772 switch (msg) {
1773 case WM_INITDIALOG:
1774 /* Accelerators used: [aco] 123abdkmprtuw */
1775 ctlposinit(&cp, hwnd);
1776 staticedit(&cp, "Terminal-&type string", IDC_TTSTATIC, IDC_TTEDIT);
1777 staticedit(&cp, "Auto-login &username", IDC_LOGSTATIC, IDC_LOGEDIT);
1778 multiedit(&cp,
1779 "&Remote command:", IDC_CMDSTATIC, IDC_CMDEDIT, 100,
1780 NULL);
1781 checkbox(&cp, "Don't allocate a &pseudo-terminal", IDC_NOPTY);
1782 checkbox(&cp, "Atte&mpt TIS or CryptoCard authentication",
1783 IDC_AUTHTIS);
1784 checkbox(&cp, "Allow &agent forwarding", IDC_AGENTFWD);
1785 editbutton(&cp, "Private &key file for authentication:",
1786 IDC_PKSTATIC, IDC_PKEDIT, "Bro&wse...", IDC_PKBUTTON);
1787 radioline(&cp, "Preferred SSH protocol version:",
1788 IDC_SSHPROTSTATIC, 2,
1789 "&1", IDC_SSHPROT1, "&2", IDC_SSHPROT2, NULL);
1790 radioline(&cp, "Preferred encryption algorithm:", IDC_CIPHERSTATIC, 3,
1791 "&3DES", IDC_CIPHER3DES,
1792 "&Blowfish", IDC_CIPHERBLOWF,
1793 "&DES", IDC_CIPHERDES, NULL);
1794
1795 SetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype);
1796 SetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username);
1797 CheckDlgButton (hwnd, IDC_NOPTY, cfg.nopty);
1798 CheckDlgButton (hwnd, IDC_AGENTFWD, cfg.agentfwd);
1799 CheckRadioButton (hwnd, IDC_CIPHER3DES, IDC_CIPHERDES,
1800 cfg.cipher == CIPHER_BLOWFISH ? IDC_CIPHERBLOWF :
1801 cfg.cipher == CIPHER_DES ? IDC_CIPHERDES :
1802 IDC_CIPHER3DES);
1803 CheckRadioButton (hwnd, IDC_SSHPROT1, IDC_SSHPROT2,
1804 cfg.sshprot == 1 ? IDC_SSHPROT1 : IDC_SSHPROT2);
1805 CheckDlgButton (hwnd, IDC_AUTHTIS, cfg.try_tis_auth);
1806 SetDlgItemText (hwnd, IDC_PKEDIT, cfg.keyfile);
1807 SetDlgItemText (hwnd, IDC_CMDEDIT, cfg.remote_cmd);
1808 break;
1809 case WM_COMMAND:
1810 switch (LOWORD(wParam)) {
1811 case IDC_TTEDIT:
1812 if (HIWORD(wParam) == EN_CHANGE)
1813 GetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype,
1814 sizeof(cfg.termtype)-1);
1815 break;
1816 case IDC_LOGEDIT:
1817 if (HIWORD(wParam) == EN_CHANGE)
1818 GetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username,
1819 sizeof(cfg.username)-1);
1820 break;
1821 case IDC_NOPTY:
1822 if (HIWORD(wParam) == BN_CLICKED ||
1823 HIWORD(wParam) == BN_DOUBLECLICKED)
1824 cfg.nopty = IsDlgButtonChecked (hwnd, IDC_NOPTY);
1825 break;
1826 case IDC_AGENTFWD:
1827 if (HIWORD(wParam) == BN_CLICKED ||
1828 HIWORD(wParam) == BN_DOUBLECLICKED)
1829 cfg.agentfwd = IsDlgButtonChecked (hwnd, IDC_AGENTFWD);
1830 break;
1831 case IDC_CIPHER3DES:
1832 case IDC_CIPHERBLOWF:
1833 case IDC_CIPHERDES:
1834 if (HIWORD(wParam) == BN_CLICKED ||
1835 HIWORD(wParam) == BN_DOUBLECLICKED) {
1836 if (IsDlgButtonChecked (hwnd, IDC_CIPHER3DES))
1837 cfg.cipher = CIPHER_3DES;
1838 else if (IsDlgButtonChecked (hwnd, IDC_CIPHERBLOWF))
1839 cfg.cipher = CIPHER_BLOWFISH;
1840 else if (IsDlgButtonChecked (hwnd, IDC_CIPHERDES))
1841 cfg.cipher = CIPHER_DES;
1842 }
1843 break;
1844 case IDC_SSHPROT1:
1845 case IDC_SSHPROT2:
1846 if (HIWORD(wParam) == BN_CLICKED ||
1847 HIWORD(wParam) == BN_DOUBLECLICKED) {
1848 if (IsDlgButtonChecked (hwnd, IDC_SSHPROT1))
1849 cfg.sshprot = 1;
1850 else if (IsDlgButtonChecked (hwnd, IDC_SSHPROT2))
1851 cfg.sshprot = 2;
1852 }
1853 break;
1854 case IDC_AUTHTIS:
1855 if (HIWORD(wParam) == BN_CLICKED ||
1856 HIWORD(wParam) == BN_DOUBLECLICKED)
1857 cfg.try_tis_auth = IsDlgButtonChecked (hwnd, IDC_AUTHTIS);
1858 break;
1859 case IDC_PKEDIT:
1860 if (HIWORD(wParam) == EN_CHANGE)
1861 GetDlgItemText (hwnd, IDC_PKEDIT, cfg.keyfile,
1862 sizeof(cfg.keyfile)-1);
1863 break;
1864 case IDC_CMDEDIT:
1865 if (HIWORD(wParam) == EN_CHANGE)
1866 GetDlgItemText (hwnd, IDC_CMDEDIT, cfg.remote_cmd,
1867 sizeof(cfg.remote_cmd)-1);
1868 break;
1869 case IDC_PKBUTTON:
1870 /*
1871 * FIXME: this crashes. Find out why.
1872 */
1873 memset(&of, 0, sizeof(of));
1874 #ifdef OPENFILENAME_SIZE_VERSION_400
1875 of.lStructSize = OPENFILENAME_SIZE_VERSION_400;
1876 #else
1877 of.lStructSize = sizeof(of);
1878 #endif
1879 of.hwndOwner = hwnd;
1880 of.lpstrFilter = "All Files\0*\0\0\0";
1881 of.lpstrCustomFilter = NULL;
1882 of.nFilterIndex = 1;
1883 of.lpstrFile = filename; strcpy(filename, cfg.keyfile);
1884 of.nMaxFile = sizeof(filename);
1885 of.lpstrFileTitle = NULL;
1886 of.lpstrInitialDir = NULL;
1887 of.lpstrTitle = "Select Public Key File";
1888 of.Flags = 0;
1889 if (GetOpenFileName(&of)) {
1890 strcpy(cfg.keyfile, filename);
1891 SetDlgItemText (hwnd, IDC_PKEDIT, cfg.keyfile);
1892 }
1893 break;
1894 }
1895 break;
1896 }
1897 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1898 }
1899
1900 static int CALLBACK SelectionProc (HWND hwnd, UINT msg,
1901 WPARAM wParam, LPARAM lParam) {
1902 struct ctlpos cp;
1903 int i;
1904 enum { controlstartvalue = 1000,
1905 IDC_MBSTATIC,
1906 IDC_MBWINDOWS,
1907 IDC_MBXTERM,
1908 IDC_CCSTATIC,
1909 IDC_CCLIST,
1910 IDC_CCSET,
1911 IDC_CCSTATIC2,
1912 IDC_CCEDIT
1913 };
1914
1915 switch (msg) {
1916 case WM_INITDIALOG:
1917 /* Accelerators used: [aco] stwx */
1918 ctlposinit(&cp, hwnd);
1919 radiobig(&cp, "Action of mouse buttons:", IDC_MBSTATIC,
1920 "&Windows (Right pastes, Middle extends)", IDC_MBWINDOWS,
1921 "&xterm (Right extends, Middle pastes)", IDC_MBXTERM,
1922 NULL);
1923 charclass(&cp, "Character classes:", IDC_CCSTATIC, IDC_CCLIST,
1924 "&Set", IDC_CCSET, IDC_CCEDIT,
1925 "&to class", IDC_CCSTATIC2);
1926
1927 CheckRadioButton (hwnd, IDC_MBWINDOWS, IDC_MBXTERM,
1928 cfg.mouse_is_xterm ? IDC_MBXTERM : IDC_MBWINDOWS);
1929 {
1930 static int tabs[4] = {25, 61, 96, 128};
1931 SendDlgItemMessage (hwnd, IDC_CCLIST, LB_SETTABSTOPS, 4,
1932 (LPARAM) tabs);
1933 }
1934 for (i=0; i<256; i++) {
1935 char str[100];
1936 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
1937 (i>=0x21 && i != 0x7F) ? i : ' ',
1938 cfg.wordness[i]);
1939 SendDlgItemMessage (hwnd, IDC_CCLIST, LB_ADDSTRING, 0,
1940 (LPARAM) str);
1941 }
1942 break;
1943 case WM_COMMAND:
1944 switch (LOWORD(wParam)) {
1945 case IDC_MBWINDOWS:
1946 case IDC_MBXTERM:
1947 cfg.mouse_is_xterm = IsDlgButtonChecked (hwnd, IDC_MBXTERM);
1948 break;
1949 case IDC_CCSET:
1950 {
1951 BOOL ok;
1952 int i;
1953 int n = GetDlgItemInt (hwnd, IDC_CCEDIT, &ok, FALSE);
1954
1955 if (!ok)
1956 MessageBeep (0);
1957 else {
1958 for (i=0; i<256; i++)
1959 if (SendDlgItemMessage (hwnd, IDC_CCLIST, LB_GETSEL,
1960 i, 0)) {
1961 char str[100];
1962 cfg.wordness[i] = n;
1963 SendDlgItemMessage (hwnd, IDC_CCLIST,
1964 LB_DELETESTRING, i, 0);
1965 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
1966 (i>=0x21 && i != 0x7F) ? i : ' ',
1967 cfg.wordness[i]);
1968 SendDlgItemMessage (hwnd, IDC_CCLIST,
1969 LB_INSERTSTRING, i,
1970 (LPARAM)str);
1971 }
1972 }
1973 }
1974 break;
1975 }
1976 break;
1977 }
1978 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1979 }
1980
1981 static int CALLBACK ColourProc (HWND hwnd, UINT msg,
1982 WPARAM wParam, LPARAM lParam) {
1983 static const char *const colours[] = {
1984 "Default Foreground", "Default Bold Foreground",
1985 "Default Background", "Default Bold Background",
1986 "Cursor Text", "Cursor Colour",
1987 "ANSI Black", "ANSI Black Bold",
1988 "ANSI Red", "ANSI Red Bold",
1989 "ANSI Green", "ANSI Green Bold",
1990 "ANSI Yellow", "ANSI Yellow Bold",
1991 "ANSI Blue", "ANSI Blue Bold",
1992 "ANSI Magenta", "ANSI Magenta Bold",
1993 "ANSI Cyan", "ANSI Cyan Bold",
1994 "ANSI White", "ANSI White Bold"
1995 };
1996 static const int permanent[] = {
1997 TRUE, FALSE, TRUE, FALSE, TRUE, TRUE,
1998 TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE,
1999 TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE
2000 };
2001 struct ctlpos cp;
2002 enum { controlstartvalue = 1000,
2003 IDC_BOLDCOLOUR,
2004 IDC_PALETTE,
2005 IDC_STATIC,
2006 IDC_LIST,
2007 IDC_RSTATIC,
2008 IDC_GSTATIC,
2009 IDC_BSTATIC,
2010 IDC_RVALUE,
2011 IDC_GVALUE,
2012 IDC_BVALUE,
2013 IDC_CHANGE
2014 };
2015
2016 switch (msg) {
2017 case WM_INITDIALOG:
2018 /* Accelerators used: [aco] bmlu */
2019 ctlposinit(&cp, hwnd);
2020 checkbox(&cp, "&Bolded text is a different colour", IDC_BOLDCOLOUR);
2021 checkbox(&cp, "Attempt to use &logical palettes", IDC_PALETTE);
2022 colouredit(&cp, "Select a colo&ur and click to modify it:",
2023 IDC_STATIC, IDC_LIST,
2024 "&Modify...", IDC_CHANGE,
2025 "Red:", IDC_RSTATIC, IDC_RVALUE,
2026 "Green:", IDC_GSTATIC, IDC_GVALUE,
2027 "Blue:", IDC_BSTATIC, IDC_BVALUE, NULL);
2028
2029 CheckDlgButton (hwnd, IDC_BOLDCOLOUR, cfg.bold_colour);
2030 CheckDlgButton (hwnd, IDC_PALETTE, cfg.try_palette);
2031 {
2032 int i;
2033 for (i=0; i<22; i++)
2034 if (cfg.bold_colour || permanent[i])
2035 SendDlgItemMessage (hwnd, IDC_LIST, LB_ADDSTRING, 0,
2036 (LPARAM) colours[i]);
2037 }
2038 SendDlgItemMessage (hwnd, IDC_LIST, LB_SETCURSEL, 0, 0);
2039 SetDlgItemInt (hwnd, IDC_RVALUE, cfg.colours[0][0], FALSE);
2040 SetDlgItemInt (hwnd, IDC_GVALUE, cfg.colours[0][1], FALSE);
2041 SetDlgItemInt (hwnd, IDC_BVALUE, cfg.colours[0][2], FALSE);
2042 break;
2043 case WM_COMMAND:
2044 switch (LOWORD(wParam)) {
2045 case IDC_BOLDCOLOUR:
2046 if (HIWORD(wParam) == BN_CLICKED ||
2047 HIWORD(wParam) == BN_DOUBLECLICKED) {
2048 int n, i;
2049 cfg.bold_colour = IsDlgButtonChecked (hwnd, IDC_BOLDCOLOUR);
2050 n = SendDlgItemMessage (hwnd, IDC_LIST, LB_GETCOUNT, 0, 0);
2051 if (cfg.bold_colour && n!=22) {
2052 for (i=0; i<22; i++)
2053 if (!permanent[i])
2054 SendDlgItemMessage (hwnd, IDC_LIST,
2055 LB_INSERTSTRING, i,
2056 (LPARAM) colours[i]);
2057 } else if (!cfg.bold_colour && n!=12) {
2058 for (i=22; i-- ;)
2059 if (!permanent[i])
2060 SendDlgItemMessage (hwnd, IDC_LIST,
2061 LB_DELETESTRING, i, 0);
2062 }
2063 }
2064 break;
2065 case IDC_PALETTE:
2066 if (HIWORD(wParam) == BN_CLICKED ||
2067 HIWORD(wParam) == BN_DOUBLECLICKED)
2068 cfg.try_palette = IsDlgButtonChecked (hwnd, IDC_PALETTE);
2069 break;
2070 case IDC_LIST:
2071 if (HIWORD(wParam) == LBN_DBLCLK ||
2072 HIWORD(wParam) == LBN_SELCHANGE) {
2073 int i = SendDlgItemMessage (hwnd, IDC_LIST, LB_GETCURSEL,
2074 0, 0);
2075 if (!cfg.bold_colour)
2076 i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
2077 SetDlgItemInt (hwnd, IDC_RVALUE, cfg.colours[i][0], FALSE);
2078 SetDlgItemInt (hwnd, IDC_GVALUE, cfg.colours[i][1], FALSE);
2079 SetDlgItemInt (hwnd, IDC_BVALUE, cfg.colours[i][2], FALSE);
2080 }
2081 break;
2082 case IDC_CHANGE:
2083 if (HIWORD(wParam) == BN_CLICKED ||
2084 HIWORD(wParam) == BN_DOUBLECLICKED) {
2085 static CHOOSECOLOR cc;
2086 static DWORD custom[16] = {0}; /* zero initialisers */
2087 int i = SendDlgItemMessage (hwnd, IDC_LIST, LB_GETCURSEL,
2088 0, 0);
2089 if (!cfg.bold_colour)
2090 i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
2091 cc.lStructSize = sizeof(cc);
2092 cc.hwndOwner = hwnd;
2093 cc.hInstance = (HWND)hinst;
2094 cc.lpCustColors = custom;
2095 cc.rgbResult = RGB (cfg.colours[i][0], cfg.colours[i][1],
2096 cfg.colours[i][2]);
2097 cc.Flags = CC_FULLOPEN | CC_RGBINIT;
2098 if (ChooseColor(&cc)) {
2099 cfg.colours[i][0] =
2100 (unsigned char) (cc.rgbResult & 0xFF);
2101 cfg.colours[i][1] =
2102 (unsigned char) (cc.rgbResult >> 8) & 0xFF;
2103 cfg.colours[i][2] =
2104 (unsigned char) (cc.rgbResult >> 16) & 0xFF;
2105 SetDlgItemInt (hwnd, IDC_RVALUE, cfg.colours[i][0],
2106 FALSE);
2107 SetDlgItemInt (hwnd, IDC_GVALUE, cfg.colours[i][1],
2108 FALSE);
2109 SetDlgItemInt (hwnd, IDC_BVALUE, cfg.colours[i][2],
2110 FALSE);
2111 }
2112 }
2113 break;
2114 }
2115 break;
2116 }
2117 return GeneralPanelProc (hwnd, msg, wParam, lParam);
2118 }
2119
2120 static int CALLBACK TranslationProc (HWND hwnd, UINT msg,
2121 WPARAM wParam, LPARAM lParam) {
2122 struct ctlpos cp;
2123 enum { controlstartvalue = 1000,
2124 IDC_XLATSTATIC,
2125 IDC_NOXLAT,
2126 IDC_KOI8WIN1251,
2127 IDC_88592WIN1250,
2128 IDC_CAPSLOCKCYR,
2129 IDC_VTSTATIC,
2130 IDC_VTXWINDOWS,
2131 IDC_VTOEMANSI,
2132 IDC_VTOEMONLY,
2133 IDC_VTPOORMAN
2134 };
2135
2136 switch (msg) {
2137 case WM_INITDIALOG:
2138 /* Accelerators used: [aco] beiknpsx */
2139 ctlposinit(&cp, hwnd);
2140 radiobig(&cp,
2141 "Handling of VT100 line drawing characters:", IDC_VTSTATIC,
2142 "Font has &XWindows encoding", IDC_VTXWINDOWS,
2143 "Use font in &both ANSI and OEM modes", IDC_VTOEMANSI,
2144 "Use font in O&EM mode only", IDC_VTOEMONLY,
2145 "&Poor man's line drawing (""+"", ""-"" and ""|"")",
2146 IDC_VTPOORMAN, NULL);
2147 radiobig(&cp,
2148 "Character set translation:", IDC_XLATSTATIC,
2149 "&None", IDC_NOXLAT,
2150 "&KOI8 / Win-1251", IDC_KOI8WIN1251,
2151 "&ISO-8859-2 / Win-1250", IDC_88592WIN1250, NULL);
2152 checkbox(&cp, "CAP&S LOCK acts as cyrillic switch", IDC_CAPSLOCKCYR);
2153
2154 CheckRadioButton (hwnd, IDC_NOXLAT, IDC_88592WIN1250,
2155 cfg.xlat_88592w1250 ? IDC_88592WIN1250 :
2156 cfg.xlat_enablekoiwin ? IDC_KOI8WIN1251 :
2157 IDC_NOXLAT);
2158 CheckDlgButton (hwnd, IDC_CAPSLOCKCYR, cfg.xlat_capslockcyr);
2159 CheckRadioButton (hwnd, IDC_VTXWINDOWS, IDC_VTPOORMAN,
2160 cfg.vtmode == VT_XWINDOWS ? IDC_VTXWINDOWS :
2161 cfg.vtmode == VT_OEMANSI ? IDC_VTOEMANSI :
2162 cfg.vtmode == VT_OEMONLY ? IDC_VTOEMONLY :
2163 IDC_VTPOORMAN);
2164 case WM_COMMAND:
2165 switch (LOWORD(wParam)) {
2166 case IDC_NOXLAT:
2167 case IDC_KOI8WIN1251:
2168 case IDC_88592WIN1250:
2169 cfg.xlat_enablekoiwin =
2170 IsDlgButtonChecked (hwnd, IDC_KOI8WIN1251);
2171 cfg.xlat_88592w1250 =
2172 IsDlgButtonChecked (hwnd, IDC_88592WIN1250);
2173 break;
2174 case IDC_CAPSLOCKCYR:
2175 if (HIWORD(wParam) == BN_CLICKED ||
2176 HIWORD(wParam) == BN_DOUBLECLICKED) {
2177 cfg.xlat_capslockcyr =
2178 IsDlgButtonChecked (hwnd, IDC_CAPSLOCKCYR);
2179 }
2180 break;
2181 case IDC_VTXWINDOWS:
2182 case IDC_VTOEMANSI:
2183 case IDC_VTOEMONLY:
2184 case IDC_VTPOORMAN:
2185 cfg.vtmode =
2186 (IsDlgButtonChecked (hwnd, IDC_VTXWINDOWS) ? VT_XWINDOWS :
2187 IsDlgButtonChecked (hwnd, IDC_VTOEMANSI) ? VT_OEMANSI :
2188 IsDlgButtonChecked (hwnd, IDC_VTOEMONLY) ? VT_OEMONLY :
2189 VT_POORMAN);
2190 break;
2191 }
2192 }
2193 return GeneralPanelProc (hwnd, msg, wParam, lParam);
2194 }
2195
2196 static DLGPROC panelproc[NPANELS] = {
2197 ConnectionProc, KeyboardProc, TerminalProc, WindowProc,
2198 TelnetProc, SshProc, SelectionProc, ColourProc, TranslationProc
2199 };
2200
2201 static char *names[NPANELS] = {
2202 "Connection", "Keyboard", "Terminal", "Window", "Telnet",
2203 "SSH", "Selection", "Colours", "Translation"
2204 };
2205
2206 static int mainp[MAIN_NPANELS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8};
2207 static int reconfp[RECONF_NPANELS] = { 1, 2, 3, 6, 7, 8};
2208
2209 static HWND makesubdialog(HWND hwnd, int x, int y, int w, int h, int n) {
2210 RECT r;
2211 HWND ret;
2212 WPARAM font;
2213 r.left = x; r.top = y;
2214 r.right = r.left + w; r.bottom = r.top + h;
2215 MapDialogRect(hwnd, &r);
2216 ret = CreateWindowEx(WS_EX_CONTROLPARENT,
2217 WC_DIALOG, "", /* no title */
2218 WS_CHILD | WS_VISIBLE | DS_SETFONT,
2219 r.left, r.top,
2220 r.right-r.left, r.bottom-r.top,
2221 hwnd, (HMENU)IDC_SUBDLG,
2222 hinst, NULL);
2223 SetWindowLong (ret, DWL_DLGPROC, (LONG)panelproc[n]);
2224 font = SendMessage(hwnd, WM_GETFONT, 0, 0);
2225 SendMessage (ret, WM_SETFONT, font, MAKELPARAM(0, 0));
2226 SendMessage (ret, WM_INITDIALOG, 0, 0);
2227 return ret;
2228 }
2229
2230 static int GenericMainDlgProc (HWND hwnd, UINT msg,
2231 WPARAM wParam, LPARAM lParam,
2232 int npanels, int *panelnums, HWND *page) {
2233 HWND hw, tabctl;
2234
2235 switch (msg) {
2236 case WM_INITDIALOG:
2237 { /* centre the window */
2238 RECT rs, rd;
2239
2240 hw = GetDesktopWindow();
2241 if (GetWindowRect (hw, &rs) && GetWindowRect (hwnd, &rd))
2242 MoveWindow (hwnd, (rs.right + rs.left + rd.left - rd.right)/2,
2243 (rs.bottom + rs.top + rd.top - rd.bottom)/2,
2244 rd.right-rd.left, rd.bottom-rd.top, TRUE);
2245 }
2246 {
2247 RECT r;
2248 r.left = 3; r.right = r.left + 174;
2249 r.top = 3; r.bottom = r.top + 193;
2250 MapDialogRect(hwnd, &r);
2251 tabctl = CreateWindowEx(0, WC_TABCONTROL, "",
2252 WS_CHILD | WS_VISIBLE |
2253 WS_TABSTOP | TCS_MULTILINE,
2254 r.left, r.top,
2255 r.right-r.left, r.bottom-r.top,
2256 hwnd, (HMENU)IDC_TAB, hinst, NULL);
2257
2258 if (!tabctl) {
2259 struct ctlpos cp;
2260 ctlposinit2(&cp, hwnd);
2261 ersatztab(&cp, "Category:", IDC_TABSTATIC1, IDC_TABLIST,
2262 IDC_TABSTATIC2);
2263 } else {
2264 WPARAM font = SendMessage(hwnd, WM_GETFONT, 0, 0);
2265 SendMessage(tabctl, WM_SETFONT, font, MAKELPARAM(TRUE, 0));
2266 }
2267 }
2268 *page = NULL;
2269 if (tabctl) { /* initialise the tab control */
2270 TC_ITEMHEADER tab;
2271 int i;
2272
2273 for (i=0; i<npanels; i++) {
2274 tab.mask = TCIF_TEXT;
2275 tab.pszText = names[panelnums[i]];
2276 TabCtrl_InsertItem (tabctl, i, &tab);
2277 }
2278 } else {
2279 int i;
2280
2281 for (i=0; i<npanels; i++) {
2282 SendDlgItemMessage(hwnd, IDC_TABLIST, CB_ADDSTRING,
2283 0, (LPARAM)names[panelnums[i]]);
2284 }
2285 SendDlgItemMessage(hwnd, IDC_TABLIST, CB_SETCURSEL, 0, 0);
2286 }
2287 *page = makesubdialog(hwnd, 6, 30, 168, 163, panelnums[0]);
2288 SetFocus (*page);
2289 return 0;
2290 case WM_NOTIFY:
2291 if (LOWORD(wParam) == IDC_TAB &&
2292 ((LPNMHDR)lParam)->code == TCN_SELCHANGE) {
2293 int i = TabCtrl_GetCurSel(((LPNMHDR)lParam)->hwndFrom);
2294 if (*page)
2295 DestroyWindow (*page);
2296 *page = makesubdialog(hwnd, 6, 30, 168, 163, panelnums[i]);
2297 SetFocus (((LPNMHDR)lParam)->hwndFrom); /* ensure focus stays */
2298 return 0;
2299 }
2300 break;
2301 case WM_COMMAND:
2302 switch (LOWORD(wParam)) {
2303 case IDC_TABLIST:
2304 if (HIWORD(wParam) == CBN_SELCHANGE) {
2305 HWND tablist = GetDlgItem (hwnd, IDC_TABLIST);
2306 int i = SendMessage (tablist, CB_GETCURSEL, 0, 0);
2307 if (*page)
2308 DestroyWindow (*page);
2309 *page = makesubdialog(hwnd, 6, 30, 168, 163, panelnums[i]);
2310 SetFocus(tablist); /* ensure focus stays */
2311 return 0;
2312 }
2313 break;
2314 case IDOK:
2315 if (*cfg.host)
2316 EndDialog (hwnd, 1);
2317 else
2318 MessageBeep (0);
2319 return 0;
2320 case IDCANCEL:
2321 EndDialog (hwnd, 0);
2322 return 0;
2323 }
2324 return 0;
2325 case WM_CLOSE:
2326 EndDialog (hwnd, 0);
2327 return 0;
2328
2329 /* Grrr Explorer will maximize Dialogs! */
2330 case WM_SIZE:
2331 if (wParam == SIZE_MAXIMIZED)
2332 force_normal(hwnd);
2333 return 0;
2334 }
2335 return 0;
2336 }
2337
2338 static int CALLBACK MainDlgProc (HWND hwnd, UINT msg,
2339 WPARAM wParam, LPARAM lParam) {
2340 static HWND page = NULL;
2341
2342 if (msg == WM_COMMAND && LOWORD(wParam) == IDOK) {
2343 }
2344 if (msg == WM_COMMAND && LOWORD(wParam) == IDC_ABOUT) {
2345 EnableWindow(hwnd, 0);
2346 DialogBox(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
2347 GetParent(hwnd), AboutProc);
2348 EnableWindow(hwnd, 1);
2349 SetActiveWindow(hwnd);
2350 }
2351 return GenericMainDlgProc (hwnd, msg, wParam, lParam,
2352 MAIN_NPANELS, mainp, &page);
2353 }
2354
2355 static int CALLBACK ReconfDlgProc (HWND hwnd, UINT msg,
2356 WPARAM wParam, LPARAM lParam) {
2357 static HWND page;
2358 return GenericMainDlgProc (hwnd, msg, wParam, lParam,
2359 RECONF_NPANELS, reconfp, &page);
2360 }
2361
2362 void get_sesslist(int allocate) {
2363 static char otherbuf[2048];
2364 static char *buffer;
2365 int buflen, bufsize, i;
2366 char *p, *ret;
2367 void *handle;
2368
2369 if (allocate) {
2370
2371 if ((handle = enum_settings_start()) == NULL)
2372 return;
2373
2374 buflen = bufsize = 0;
2375 buffer = NULL;
2376 do {
2377 ret = enum_settings_next(handle, otherbuf, sizeof(otherbuf));
2378 if (ret) {
2379 int len = strlen(otherbuf)+1;
2380 if (bufsize < buflen+len) {
2381 bufsize = buflen + len + 2048;
2382 buffer = srealloc(buffer, bufsize);
2383 }
2384 strcpy(buffer+buflen, otherbuf);
2385 buflen += strlen(buffer+buflen)+1;
2386 }
2387 } while (ret);
2388 enum_settings_finish(handle);
2389 buffer = srealloc(buffer, buflen+1);
2390 buffer[buflen] = '\0';
2391
2392 p = buffer;
2393 nsessions = 1; /* "Default Settings" counts as one */
2394 while (*p) {
2395 if (strcmp(p, "Default Settings"))
2396 nsessions++;
2397 while (*p) p++;
2398 p++;
2399 }
2400
2401 sessions = smalloc(nsessions * sizeof(char *));
2402 sessions[0] = "Default Settings";
2403 p = buffer;
2404 i = 1;
2405 while (*p) {
2406 if (strcmp(p, "Default Settings"))
2407 sessions[i++] = p;
2408 while (*p) p++;
2409 p++;
2410 }
2411 } else {
2412 sfree (buffer);
2413 sfree (sessions);
2414 }
2415 }
2416
2417 int do_config (void) {
2418 int ret;
2419
2420 get_sesslist(TRUE);
2421 savedsession[0] = '\0';
2422 ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_MAINBOX), NULL, MainDlgProc);
2423 get_sesslist(FALSE);
2424
2425 return ret;
2426 }
2427
2428 int do_reconfig (HWND hwnd) {
2429 Config backup_cfg;
2430 int ret;
2431
2432 backup_cfg = cfg; /* structure copy */
2433 ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_RECONF), hwnd, ReconfDlgProc);
2434 if (!ret)
2435 cfg = backup_cfg; /* structure copy */
2436 else
2437 force_normal(hwnd);
2438
2439 return ret;
2440 }
2441
2442 void do_defaults (char *session) {
2443 if (session)
2444 load_settings (session, TRUE);
2445 else
2446 load_settings ("Default Settings", FALSE);
2447 }
2448
2449 void logevent (char *string) {
2450 if (nevents >= negsize) {
2451 negsize += 64;
2452 events = srealloc (events, negsize * sizeof(*events));
2453 }
2454 events[nevents] = smalloc(1+strlen(string));
2455 strcpy (events[nevents], string);
2456 nevents++;
2457 if (logbox) {
2458 int count;
2459 SendDlgItemMessage (logbox, IDN_LIST, LB_ADDSTRING,
2460 0, (LPARAM)string);
2461 count = SendDlgItemMessage (logbox, IDN_LIST, LB_GETCOUNT, 0, 0);
2462 SendDlgItemMessage (logbox, IDN_LIST, LB_SETTOPINDEX, count-1, 0);
2463 }
2464 }
2465
2466 void showeventlog (HWND hwnd) {
2467 if (!logbox) {
2468 logbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_LOGBOX),
2469 hwnd, LogProc);
2470 ShowWindow (logbox, SW_SHOWNORMAL);
2471 }
2472 }
2473
2474 void showabout (HWND hwnd) {
2475 if (!abtbox) {
2476 abtbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
2477 hwnd, AboutProc);
2478 ShowWindow (abtbox, SW_SHOWNORMAL);
2479 }
2480 }
2481
2482 void verify_ssh_host_key(char *host, int port, char *keytype,
2483 char *keystr, char *fingerprint) {
2484 int ret;
2485
2486 static const char absentmsg[] =
2487 "The server's host key is not cached in the registry. You\n"
2488 "have no guarantee that the server is the computer you\n"
2489 "think it is.\n"
2490 "The server's key fingerprint is:\n"
2491 "%s\n"
2492 "If you trust this host, hit Yes to add the key to\n"
2493 "PuTTY's cache and carry on connecting.\n"
2494 "If you do not trust this host, hit No to abandon the\n"
2495 "connection.\n";
2496
2497 static const char wrongmsg[] =
2498 "WARNING - POTENTIAL SECURITY BREACH!\n"
2499 "\n"
2500 "The server's host key does not match the one PuTTY has\n"
2501 "cached in the registry. This means that either the\n"
2502 "server administrator has changed the host key, or you\n"
2503 "have actually connected to another computer pretending\n"
2504 "to be the server.\n"
2505 "The new key fingerprint is:\n"
2506 "%s\n"
2507 "If you were expecting this change and trust the new key,\n"
2508 "hit Yes to update PuTTY's cache and continue connecting.\n"
2509 "If you want to carry on connecting but without updating\n"
2510 "the cache, hit No.\n"
2511 "If you want to abandon the connection completely, hit\n"
2512 "Cancel. Hitting Cancel is the ONLY guaranteed safe\n"
2513 "choice.\n";
2514
2515 static const char mbtitle[] = "PuTTY Security Alert";
2516
2517
2518 char message[160+ /* sensible fingerprint max size */
2519 (sizeof(absentmsg) > sizeof(wrongmsg) ?
2520 sizeof(absentmsg) : sizeof(wrongmsg))];
2521
2522 /*
2523 * Verify the key against the registry.
2524 */
2525 ret = verify_host_key(host, port, keytype, keystr);
2526
2527 if (ret == 0) /* success - key matched OK */
2528 return;
2529 if (ret == 2) { /* key was different */
2530 int mbret;
2531 sprintf(message, wrongmsg, fingerprint);
2532 mbret = MessageBox(NULL, message, mbtitle,
2533 MB_ICONWARNING | MB_YESNOCANCEL);
2534 if (mbret == IDYES)
2535 store_host_key(host, port, keytype, keystr);
2536 if (mbret == IDCANCEL)
2537 exit(0);
2538 }
2539 if (ret == 1) { /* key was absent */
2540 int mbret;
2541 sprintf(message, absentmsg, fingerprint);
2542 mbret = MessageBox(NULL, message, mbtitle,
2543 MB_ICONWARNING | MB_YESNO);
2544 if (mbret == IDNO)
2545 exit(0);
2546 store_host_key(host, port, keytype, keystr);
2547 }
2548 }