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