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