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