Rename IDC_FUNCTILDE from "VT400" to "ESC[n~" because another VT400 now
[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_88592CP852,
1001 IDC_CAPSLOCKCYR,
1002 IDC_VTSTATIC,
1003 IDC_VTXWINDOWS,
1004 IDC_VTOEMANSI,
1005 IDC_VTOEMONLY,
1006 IDC_VTPOORMAN,
1007 translationpanelend,
1008
1009 controlendvalue
1010 };
1011
1012 static const char *const colours[] = {
1013 "Default Foreground", "Default Bold Foreground",
1014 "Default Background", "Default Bold Background",
1015 "Cursor Text", "Cursor Colour",
1016 "ANSI Black", "ANSI Black Bold",
1017 "ANSI Red", "ANSI Red Bold",
1018 "ANSI Green", "ANSI Green Bold",
1019 "ANSI Yellow", "ANSI Yellow Bold",
1020 "ANSI Blue", "ANSI Blue Bold",
1021 "ANSI Magenta", "ANSI Magenta Bold",
1022 "ANSI Cyan", "ANSI Cyan Bold",
1023 "ANSI White", "ANSI White Bold"
1024 };
1025 static const int permcolour[] = {
1026 TRUE, FALSE, TRUE, FALSE, TRUE, TRUE,
1027 TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE,
1028 TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE
1029 };
1030
1031 static void fmtfont (char *buf) {
1032 sprintf (buf, "Font: %s, ", cfg.font);
1033 if (cfg.fontisbold)
1034 strcat(buf, "bold, ");
1035 if (cfg.fontheight == 0)
1036 strcat (buf, "default height");
1037 else
1038 sprintf (buf+strlen(buf), "%d-%s",
1039 (cfg.fontheight < 0 ? -cfg.fontheight : cfg.fontheight),
1040 (cfg.fontheight < 0 ? "pixel" : "point"));
1041 }
1042
1043 static void init_dlg_ctrls(HWND hwnd) {
1044 int i;
1045 char fontstatic[256];
1046
1047 SetDlgItemText (hwnd, IDC_HOST, cfg.host);
1048 SetDlgItemText (hwnd, IDC_SESSEDIT, savedsession);
1049 SetDlgItemInt (hwnd, IDC_PORT, cfg.port, FALSE);
1050 for (i = 0; i < nsessions; i++)
1051 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_ADDSTRING,
1052 0, (LPARAM) (sessions[i]));
1053 CheckRadioButton (hwnd, IDC_PROTRAW, IDC_PROTSSH,
1054 cfg.protocol==PROT_SSH ? IDC_PROTSSH :
1055 cfg.protocol==PROT_TELNET ? IDC_PROTTELNET : IDC_PROTRAW );
1056 SetDlgItemInt (hwnd, IDC_PINGEDIT, cfg.ping_interval, FALSE);
1057
1058 CheckRadioButton (hwnd, IDC_DEL008, IDC_DEL127,
1059 cfg.bksp_is_delete ? IDC_DEL127 : IDC_DEL008);
1060 CheckRadioButton (hwnd, IDC_HOMETILDE, IDC_HOMERXVT,
1061 cfg.rxvt_homeend ? IDC_HOMERXVT : IDC_HOMETILDE);
1062 CheckRadioButton (hwnd, IDC_FUNCTILDE, IDC_FUNCXTERM,
1063 cfg.funky_type == 0 ? IDC_FUNCTILDE :
1064 cfg.funky_type == 1 ? IDC_FUNCLINUX :
1065 cfg.funky_type == 2 ? IDC_FUNCXTERM :
1066 cfg.funky_type == 3 ? IDC_FUNCVT400 :
1067 IDC_FUNCTILDE );
1068 CheckRadioButton (hwnd, IDC_CURNORMAL, IDC_CURAPPLIC,
1069 cfg.app_cursor ? IDC_CURAPPLIC : IDC_CURNORMAL);
1070 CheckRadioButton (hwnd, IDC_KPNORMAL, IDC_KPNH,
1071 cfg.nethack_keypad ? IDC_KPNH :
1072 cfg.app_keypad ? IDC_KPAPPLIC : IDC_KPNORMAL);
1073 CheckDlgButton (hwnd, IDC_ALTF4, cfg.alt_f4);
1074 CheckDlgButton (hwnd, IDC_ALTSPACE, cfg.alt_space);
1075 CheckDlgButton (hwnd, IDC_LDISCTERM, cfg.ldisc_term);
1076 CheckDlgButton (hwnd, IDC_SCROLLKEY, cfg.scroll_on_key);
1077
1078 CheckDlgButton (hwnd, IDC_WRAPMODE, cfg.wrap_mode);
1079 CheckDlgButton (hwnd, IDC_DECOM, cfg.dec_om);
1080 CheckDlgButton (hwnd, IDC_LFHASCR, cfg.lfhascr);
1081 SetDlgItemInt (hwnd, IDC_ROWSEDIT, cfg.height, FALSE);
1082 SetDlgItemInt (hwnd, IDC_COLSEDIT, cfg.width, FALSE);
1083 SetDlgItemInt (hwnd, IDC_SAVEEDIT, cfg.savelines, FALSE);
1084 fmtfont (fontstatic);
1085 SetDlgItemText (hwnd, IDC_FONTSTATIC, fontstatic);
1086 CheckDlgButton (hwnd, IDC_BEEP, cfg.beep);
1087 CheckDlgButton (hwnd, IDC_BCE, cfg.bce);
1088 CheckDlgButton (hwnd, IDC_BLINKTEXT, cfg.blinktext);
1089
1090 SetDlgItemText (hwnd, IDC_WINEDIT, cfg.wintitle);
1091 CheckDlgButton (hwnd, IDC_WINNAME, cfg.win_name_always);
1092 CheckDlgButton (hwnd, IDC_BLINKCUR, cfg.blink_cur);
1093 CheckDlgButton (hwnd, IDC_SCROLLBAR, cfg.scrollbar);
1094 CheckDlgButton (hwnd, IDC_LOCKSIZE, cfg.locksize);
1095 CheckDlgButton (hwnd, IDC_CLOSEEXIT, cfg.close_on_exit);
1096 CheckDlgButton (hwnd, IDC_CLOSEWARN, cfg.warn_on_close);
1097
1098 SetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype);
1099 SetDlgItemText (hwnd, IDC_TSEDIT, cfg.termspeed);
1100 SetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username);
1101 {
1102 char *p = cfg.environmt;
1103 while (*p) {
1104 SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_ADDSTRING, 0,
1105 (LPARAM) p);
1106 p += strlen(p)+1;
1107 }
1108 }
1109 CheckRadioButton (hwnd, IDC_EMBSD, IDC_EMRFC,
1110 cfg.rfc_environ ? IDC_EMRFC : IDC_EMBSD);
1111
1112 SetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype);
1113 SetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username);
1114 CheckDlgButton (hwnd, IDC_NOPTY, cfg.nopty);
1115 CheckDlgButton (hwnd, IDC_AGENTFWD, cfg.agentfwd);
1116 CheckRadioButton (hwnd, IDC_CIPHER3DES, IDC_CIPHERDES,
1117 cfg.cipher == CIPHER_BLOWFISH ? IDC_CIPHERBLOWF :
1118 cfg.cipher == CIPHER_DES ? IDC_CIPHERDES :
1119 IDC_CIPHER3DES);
1120 CheckRadioButton (hwnd, IDC_SSHPROT1, IDC_SSHPROT2,
1121 cfg.sshprot == 1 ? IDC_SSHPROT1 : IDC_SSHPROT2);
1122 CheckDlgButton (hwnd, IDC_AUTHTIS, cfg.try_tis_auth);
1123 SetDlgItemText (hwnd, IDC_PKEDIT, cfg.keyfile);
1124 SetDlgItemText (hwnd, IDC_CMDEDIT, cfg.remote_cmd);
1125
1126 CheckRadioButton (hwnd, IDC_MBWINDOWS, IDC_MBXTERM,
1127 cfg.mouse_is_xterm ? IDC_MBXTERM : IDC_MBWINDOWS);
1128 {
1129 static int tabs[4] = {25, 61, 96, 128};
1130 SendDlgItemMessage (hwnd, IDC_CCLIST, LB_SETTABSTOPS, 4,
1131 (LPARAM) tabs);
1132 }
1133 for (i=0; i<256; i++) {
1134 char str[100];
1135 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
1136 (i>=0x21 && i != 0x7F) ? i : ' ',
1137 cfg.wordness[i]);
1138 SendDlgItemMessage (hwnd, IDC_CCLIST, LB_ADDSTRING, 0,
1139 (LPARAM) str);
1140 }
1141
1142 CheckDlgButton (hwnd, IDC_BOLDCOLOUR, cfg.bold_colour);
1143 CheckDlgButton (hwnd, IDC_PALETTE, cfg.try_palette);
1144 {
1145 int i;
1146 for (i=0; i<22; i++)
1147 if (cfg.bold_colour || permcolour[i])
1148 SendDlgItemMessage (hwnd, IDC_LIST, LB_ADDSTRING, 0,
1149 (LPARAM) colours[i]);
1150 }
1151 SendDlgItemMessage (hwnd, IDC_LIST, LB_SETCURSEL, 0, 0);
1152 SetDlgItemInt (hwnd, IDC_RVALUE, cfg.colours[0][0], FALSE);
1153 SetDlgItemInt (hwnd, IDC_GVALUE, cfg.colours[0][1], FALSE);
1154 SetDlgItemInt (hwnd, IDC_BVALUE, cfg.colours[0][2], FALSE);
1155
1156 CheckRadioButton (hwnd, IDC_NOXLAT, IDC_88592CP852,
1157 cfg.xlat_88592w1250 ? IDC_88592WIN1250 :
1158 cfg.xlat_88592cp852 ? IDC_88592CP852 :
1159 cfg.xlat_enablekoiwin ? IDC_KOI8WIN1251 :
1160 IDC_NOXLAT);
1161 CheckDlgButton (hwnd, IDC_CAPSLOCKCYR, cfg.xlat_capslockcyr);
1162 CheckRadioButton (hwnd, IDC_VTXWINDOWS, IDC_VTPOORMAN,
1163 cfg.vtmode == VT_XWINDOWS ? IDC_VTXWINDOWS :
1164 cfg.vtmode == VT_OEMANSI ? IDC_VTOEMANSI :
1165 cfg.vtmode == VT_OEMONLY ? IDC_VTOEMONLY :
1166 IDC_VTPOORMAN);
1167 }
1168
1169 static void hide(HWND hwnd, int hide, int minid, int maxid) {
1170 int i;
1171 for (i = minid; i < maxid; i++) {
1172 HWND ctl = GetDlgItem(hwnd, i);
1173 if (ctl) {
1174 ShowWindow(ctl, hide ? SW_HIDE : SW_SHOW);
1175 }
1176 }
1177 }
1178
1179 struct treeview_faff {
1180 HWND treeview;
1181 HTREEITEM lastat[4];
1182 };
1183
1184 static HTREEITEM treeview_insert(struct treeview_faff *faff,
1185 int level, char *text) {
1186 TVINSERTSTRUCT ins;
1187 int i;
1188 HTREEITEM newitem;
1189 ins.hParent = (level > 0 ? faff->lastat[level-1] : TVI_ROOT);
1190 ins.hInsertAfter = faff->lastat[level];
1191 #if _WIN32_IE >= 0x0400 && defined NONAMELESSUNION
1192 #define INSITEM DUMMYUNIONNAME.item
1193 #else
1194 #define INSITEM item
1195 #endif
1196 ins.INSITEM.mask = TVIF_TEXT;
1197 ins.INSITEM.pszText = text;
1198 newitem = TreeView_InsertItem(faff->treeview, &ins);
1199 if (level > 0)
1200 TreeView_Expand(faff->treeview, faff->lastat[level-1], TVE_EXPAND);
1201 faff->lastat[level] = newitem;
1202 for (i = level+1; i < 4; i++) faff->lastat[i] = NULL;
1203 return newitem;
1204 }
1205
1206 /*
1207 * This _huge_ function is the configuration box.
1208 */
1209 static int GenericMainDlgProc (HWND hwnd, UINT msg,
1210 WPARAM wParam, LPARAM lParam,
1211 int dlgtype) {
1212 HWND hw, treeview;
1213 struct treeview_faff tvfaff;
1214 HTREEITEM hsession;
1215 OPENFILENAME of;
1216 char filename[sizeof(cfg.keyfile)];
1217 CHOOSEFONT cf;
1218 LOGFONT lf;
1219 char fontstatic[256];
1220 int i;
1221
1222 switch (msg) {
1223 case WM_INITDIALOG:
1224 SetWindowLong(hwnd, GWL_USERDATA, 0);
1225 /*
1226 * Centre the window.
1227 */
1228 { /* centre the window */
1229 RECT rs, rd;
1230
1231 hw = GetDesktopWindow();
1232 if (GetWindowRect (hw, &rs) && GetWindowRect (hwnd, &rd))
1233 MoveWindow (hwnd, (rs.right + rs.left + rd.left - rd.right)/2,
1234 (rs.bottom + rs.top + rd.top - rd.bottom)/2,
1235 rd.right-rd.left, rd.bottom-rd.top, TRUE);
1236 }
1237
1238 /*
1239 * Create the tree view.
1240 */
1241 {
1242 RECT r;
1243 WPARAM font;
1244 HWND tvstatic;
1245
1246 r.left = 3; r.right = r.left + 75;
1247 r.top = 3; r.bottom = r.top + 10;
1248 MapDialogRect(hwnd, &r);
1249 tvstatic = CreateWindowEx(0, "STATIC", "Cate&gory:",
1250 WS_CHILD | WS_VISIBLE,
1251 r.left, r.top,
1252 r.right-r.left, r.bottom-r.top,
1253 hwnd, (HMENU)IDCX_TVSTATIC, hinst, NULL);
1254 font = SendMessage(hwnd, WM_GETFONT, 0, 0);
1255 SendMessage(tvstatic, WM_SETFONT, font, MAKELPARAM(TRUE, 0));
1256
1257 r.left = 3; r.right = r.left + 75;
1258 r.top = 13; r.bottom = r.top + 196;
1259 MapDialogRect(hwnd, &r);
1260 treeview = CreateWindowEx(WS_EX_CLIENTEDGE, WC_TREEVIEW, "",
1261 WS_CHILD | WS_VISIBLE |
1262 WS_TABSTOP | TVS_HASLINES |
1263 TVS_DISABLEDRAGDROP | TVS_HASBUTTONS |
1264 TVS_LINESATROOT | TVS_SHOWSELALWAYS,
1265 r.left, r.top,
1266 r.right-r.left, r.bottom-r.top,
1267 hwnd, (HMENU)IDCX_TREEVIEW, hinst, NULL);
1268 font = SendMessage(hwnd, WM_GETFONT, 0, 0);
1269 SendMessage(treeview, WM_SETFONT, font, MAKELPARAM(TRUE, 0));
1270 tvfaff.treeview = treeview;
1271 memset(tvfaff.lastat, 0, sizeof(tvfaff.lastat));
1272 }
1273
1274 /*
1275 * Create the various panelfuls of controls.
1276 */
1277
1278 /* The Session panel. Accelerators used: [acgo] nprthelsdx */
1279 {
1280 struct ctlpos cp;
1281 ctlposinit(&cp, hwnd, 80, 3, 13);
1282 bartitle(&cp, "Basic options for your PuTTY session",
1283 IDC_TITLE_SESSION);
1284 if (dlgtype == 0) {
1285 beginbox(&cp, "Specify your connection by host name",
1286 IDC_BOX_SESSION1, IDC_BOXT_SESSION1);
1287 multiedit(&cp,
1288 "Host &Name", IDC_HOSTSTATIC, IDC_HOST, 75,
1289 "&Port", IDC_PORTSTATIC, IDC_PORT, 25, NULL);
1290 if (backends[2].backend == NULL) {
1291 /* this is PuTTYtel, so only two protocols available */
1292 radioline(&cp, "Protocol:", IDC_PROTSTATIC, 3,
1293 "&Raw", IDC_PROTRAW,
1294 "&Telnet", IDC_PROTTELNET, NULL);
1295 } else {
1296 radioline(&cp, "Protocol:", IDC_PROTSTATIC, 3,
1297 "&Raw", IDC_PROTRAW,
1298 "&Telnet", IDC_PROTTELNET,
1299 #ifdef FWHACK
1300 "SS&H/hack",
1301 #else
1302 "SS&H",
1303 #endif
1304 IDC_PROTSSH, NULL);
1305 }
1306 endbox(&cp);
1307 beginbox(&cp, "Load, save or delete a stored session",
1308 IDC_BOX_SESSION2, IDC_BOXT_SESSION2);
1309 sesssaver(&cp, "Stor&ed Sessions",
1310 IDC_SESSSTATIC, IDC_SESSEDIT, IDC_SESSLIST,
1311 "&Load", IDC_SESSLOAD,
1312 "&Save", IDC_SESSSAVE,
1313 "&Delete", IDC_SESSDEL, NULL);
1314 endbox(&cp);
1315 }
1316 beginbox(&cp, NULL, IDC_BOX_SESSION3, 0);
1317 checkbox(&cp, "Close Window on E&xit", IDC_CLOSEEXIT);
1318 endbox(&cp);
1319
1320 hsession = treeview_insert(&tvfaff, 0, "Session");
1321 }
1322
1323 /* The Terminal panel. Accelerators used: [acgo] rmkh&dlbenu */
1324 {
1325 struct ctlpos cp;
1326 ctlposinit(&cp, hwnd, 80, 3, 13);
1327 bartitle(&cp, "Options controlling the terminal emulation",
1328 IDC_TITLE_TERMINAL);
1329 beginbox(&cp, "Set the size of the terminal window",
1330 IDC_BOX_TERMINAL1, IDC_BOXT_TERMINAL1);
1331 multiedit(&cp,
1332 "&Rows", IDC_ROWSSTATIC, IDC_ROWSEDIT, 50,
1333 "Colu&mns", IDC_COLSSTATIC, IDC_COLSEDIT, 50,
1334 NULL);
1335 checkbox(&cp, "Loc&k window size against resizing", IDC_LOCKSIZE);
1336 endbox(&cp);
1337 beginbox(&cp, "Set the font used in the terminal window",
1338 IDC_BOX_TERMINAL2, IDC_BOXT_TERMINAL2);
1339 staticbtn(&cp, "", IDC_FONTSTATIC, "C&hange...", IDC_CHOOSEFONT);
1340 endbox(&cp);
1341 beginbox(&cp, "Set various terminal options",
1342 IDC_BOX_TERMINAL3, IDC_BOXT_TERMINAL3);
1343 checkbox(&cp, "Auto &wrap mode initially on", IDC_WRAPMODE);
1344 checkbox(&cp, "&DEC Origin Mode initially on", IDC_DECOM);
1345 checkbox(&cp, "Implicit CR in every &LF", IDC_LFHASCR);
1346 checkbox(&cp, "&Beep enabled", IDC_BEEP);
1347 checkbox(&cp, "Use background colour to &erase screen", IDC_BCE);
1348 checkbox(&cp, "Enable bli&nking text", IDC_BLINKTEXT);
1349 checkbox(&cp, "&Use local terminal line discipline", IDC_LDISCTERM);
1350 endbox(&cp);
1351
1352 treeview_insert(&tvfaff, 0, "Terminal");
1353 }
1354
1355 /* The Keyboard panel. Accelerators used: [acgo] h?srvlxvnpmie */
1356 {
1357 struct ctlpos cp;
1358 ctlposinit(&cp, hwnd, 80, 3, 13);
1359 bartitle(&cp, "Options controlling the effects of keys",
1360 IDC_TITLE_KEYBOARD);
1361 beginbox(&cp, "Change the sequences sent by:",
1362 IDC_BOX_KEYBOARD1, IDC_BOXT_KEYBOARD1);
1363 radioline(&cp, "The Backspace key", IDC_DELSTATIC, 2,
1364 "Control-&H", IDC_DEL008,
1365 "Control-&? (127)", IDC_DEL127, NULL);
1366 radioline(&cp, "The Home and End keys", IDC_HOMESTATIC, 2,
1367 "&Standard", IDC_HOMETILDE,
1368 "&rxvt", IDC_HOMERXVT, NULL);
1369 radioline(&cp, "The Function keys and keypad", IDC_FUNCSTATIC, 4,
1370 "ESC[n&~", IDC_FUNCTILDE,
1371 "&Linux", IDC_FUNCLINUX,
1372 "&Xterm R6", IDC_FUNCXTERM,
1373 "&VT400", IDC_FUNCVT400, NULL);
1374 endbox(&cp);
1375 beginbox(&cp, "Change the initial state of:",
1376 IDC_BOX_KEYBOARD2, IDC_BOXT_KEYBOARD2);
1377 radioline(&cp, "Initial state of cursor keys:", IDC_CURSTATIC, 2,
1378 "&Normal", IDC_CURNORMAL,
1379 "A&pplication", IDC_CURAPPLIC, NULL);
1380 radioline(&cp, "Initial state of numeric keypad:", IDC_KPSTATIC, 3,
1381 "Nor&mal", IDC_KPNORMAL,
1382 "Appl&ication", IDC_KPAPPLIC,
1383 "N&etHack", IDC_KPNH, NULL);
1384 endbox(&cp);
1385
1386 treeview_insert(&tvfaff, 1, "Keyboard");
1387 }
1388
1389 /* The Window panel. Accelerators used: [acgo] tibsdkw4y */
1390 {
1391 struct ctlpos cp;
1392 ctlposinit(&cp, hwnd, 80, 3, 13);
1393 bartitle(&cp, "Options controlling PuTTY's window",
1394 IDC_TITLE_WINDOW);
1395 beginbox(&cp, "Adjust the use of the window title",
1396 IDC_BOX_WINDOW1, IDC_BOXT_WINDOW1);
1397 if (dlgtype == 0)
1398 multiedit(&cp,
1399 "Initial window &title:", IDC_WINTITLE,
1400 IDC_WINEDIT, 100, NULL);
1401 checkbox(&cp, "Avoid ever using &icon title", IDC_WINNAME);
1402 endbox(&cp);
1403 beginbox(&cp, "Adjust the use of the cursor",
1404 IDC_BOX_WINDOW2, IDC_BOXT_WINDOW2);
1405 checkbox(&cp, "Cursor &blinks", IDC_BLINKCUR);
1406 endbox(&cp);
1407 beginbox(&cp, "Control the scrollback in the window",
1408 IDC_BOX_WINDOW3, IDC_BOXT_WINDOW3);
1409 staticedit(&cp, "Lines of &scrollback",
1410 IDC_SAVESTATIC, IDC_SAVEEDIT, 50);
1411 checkbox(&cp, "&Display scrollbar", IDC_SCROLLBAR);
1412 checkbox(&cp, "Reset scrollback on &keypress", IDC_SCROLLKEY);
1413 endbox(&cp);
1414 beginbox(&cp, NULL, IDC_BOX_WINDOW4, 0);
1415 checkbox(&cp, "&Warn before closing window", IDC_CLOSEWARN);
1416 checkbox(&cp, "Window closes on ALT-F&4", IDC_ALTF4);
1417 checkbox(&cp, "S&ystem menu appears on ALT-Space)", IDC_ALTSPACE);
1418 endbox(&cp);
1419
1420 treeview_insert(&tvfaff, 0, "Window");
1421 }
1422
1423 /* The Translation panel. Accelerators used: [acgo] xbepnkis */
1424 {
1425 struct ctlpos cp;
1426 ctlposinit(&cp, hwnd, 80, 3, 13);
1427 bartitle(&cp, "Options controlling character set translation",
1428 IDC_TITLE_TRANSLATION);
1429 beginbox(&cp, "Adjust how PuTTY displays line drawing characters",
1430 IDC_BOX_TRANSLATION1, IDC_BOXT_TRANSLATION1);
1431 radiobig(&cp,
1432 "Handling of line drawing characters:", IDC_VTSTATIC,
1433 "Font has &XWindows encoding", IDC_VTXWINDOWS,
1434 "Use font in &both ANSI and OEM modes", IDC_VTOEMANSI,
1435 "Use font in O&EM mode only", IDC_VTOEMONLY,
1436 "&Poor man's line drawing (""+"", ""-"" and ""|"")",
1437 IDC_VTPOORMAN, NULL);
1438 endbox(&cp);
1439 beginbox(&cp, "Enable character set translation on received data",
1440 IDC_BOX_TRANSLATION2, IDC_BOXT_TRANSLATION2);
1441 radiobig(&cp,
1442 "Character set translation:", IDC_XLATSTATIC,
1443 "&None", IDC_NOXLAT,
1444 "&KOI8 / Win-1251", IDC_KOI8WIN1251,
1445 "&ISO-8859-2 / Win-1250", IDC_88592WIN1250,
1446 "&ISO-8859-2 / CP852", IDC_88592CP852, NULL);
1447 endbox(&cp);
1448 beginbox(&cp, "Enable character set translation on input data",
1449 IDC_BOX_TRANSLATION3, IDC_BOXT_TRANSLATION3);
1450 checkbox(&cp, "CAP&S LOCK acts as cyrillic switch",
1451 IDC_CAPSLOCKCYR);
1452 endbox(&cp);
1453
1454 treeview_insert(&tvfaff, 1, "Translation");
1455 }
1456
1457 /* The Selection panel. Accelerators used: [acgo] wxst */
1458 {
1459 struct ctlpos cp;
1460 ctlposinit(&cp, hwnd, 80, 3, 13);
1461 bartitle(&cp, "Options controlling copy and paste",
1462 IDC_TITLE_SELECTION);
1463 beginbox(&cp, "Control which mouse button does which thing",
1464 IDC_BOX_SELECTION1, IDC_BOXT_SELECTION1);
1465 radiobig(&cp, "Action of mouse buttons:", IDC_MBSTATIC,
1466 "&Windows (Right pastes, Middle extends)", IDC_MBWINDOWS,
1467 "&xterm (Right extends, Middle pastes)", IDC_MBXTERM,
1468 NULL);
1469 endbox(&cp);
1470 beginbox(&cp, "Control the select-one-word-at-a-time mode",
1471 IDC_BOX_SELECTION2, IDC_BOXT_SELECTION2);
1472 charclass(&cp, "Character classes:", IDC_CCSTATIC, IDC_CCLIST,
1473 "&Set", IDC_CCSET, IDC_CCEDIT,
1474 "&to class", IDC_CCSTATIC2);
1475 endbox(&cp);
1476
1477 treeview_insert(&tvfaff, 1, "Selection");
1478 }
1479
1480 /* The Colours panel. Accelerators used: [acgo] blum */
1481 {
1482 struct ctlpos cp;
1483 ctlposinit(&cp, hwnd, 80, 3, 13);
1484 bartitle(&cp, "Options controlling use of colours",
1485 IDC_TITLE_COLOURS);
1486 beginbox(&cp, "General options for colour usage",
1487 IDC_BOX_COLOURS1, IDC_BOXT_COLOURS1);
1488 checkbox(&cp, "&Bolded text is a different colour", IDC_BOLDCOLOUR);
1489 checkbox(&cp, "Attempt to use &logical palettes", IDC_PALETTE);
1490 endbox(&cp);
1491 beginbox(&cp, "Adjust the precise colours PuTTY displays",
1492 IDC_BOX_COLOURS2, IDC_BOXT_COLOURS2);
1493 colouredit(&cp, "Select a colo&ur and then click to modify it:",
1494 IDC_STATIC, IDC_LIST,
1495 "&Modify...", IDC_CHANGE,
1496 "Red:", IDC_RSTATIC, IDC_RVALUE,
1497 "Green:", IDC_GSTATIC, IDC_GVALUE,
1498 "Blue:", IDC_BSTATIC, IDC_BVALUE, NULL);
1499 endbox(&cp);
1500
1501 treeview_insert(&tvfaff, 1, "Colours");
1502 }
1503
1504 /* The Connection panel. Accelerators used: [acgo] tuk */
1505 {
1506 struct ctlpos cp;
1507 ctlposinit(&cp, hwnd, 80, 3, 13);
1508 bartitle(&cp, "Options controlling the connection", IDC_TITLE_CONNECTION);
1509 if (dlgtype == 0) {
1510 beginbox(&cp, "Data to send to the server",
1511 IDC_BOX_CONNECTION1, IDC_BOXT_CONNECTION1);
1512 staticedit(&cp, "Terminal-&type string", IDC_TTSTATIC, IDC_TTEDIT, 50);
1513 staticedit(&cp, "Auto-login &username", IDC_LOGSTATIC, IDC_LOGEDIT, 50);
1514 endbox(&cp);
1515 }
1516 beginbox(&cp, "Sending of null packets to keep session active",
1517 IDC_BOX_CONNECTION2, IDC_BOXT_CONNECTION2);
1518 staticedit(&cp, "Minutes between &keepalives (0 to turn off)",
1519 IDC_PINGSTATIC, IDC_PINGEDIT, 25);
1520 endbox(&cp);
1521
1522 treeview_insert(&tvfaff, 0, "Connection");
1523 }
1524
1525 /* The Telnet panel. Accelerators used: [acgo] svldrbf */
1526 {
1527 struct ctlpos cp;
1528 ctlposinit(&cp, hwnd, 80, 3, 13);
1529 if (dlgtype == 0) {
1530 bartitle(&cp, "Options controlling Telnet connections", IDC_TITLE_TELNET);
1531 beginbox(&cp, "Data to send to the server",
1532 IDC_BOX_TELNET1, IDC_BOXT_TELNET1);
1533 staticedit(&cp, "Terminal-&speed string", IDC_TSSTATIC, IDC_TSEDIT, 50);
1534 envsetter(&cp, "Environment variables:", IDC_ENVSTATIC,
1535 "&Variable", IDC_VARSTATIC, IDC_VAREDIT,
1536 "Va&lue", IDC_VALSTATIC, IDC_VALEDIT,
1537 IDC_ENVLIST,
1538 "A&dd", IDC_ENVADD, "&Remove", IDC_ENVREMOVE);
1539 endbox(&cp);
1540 beginbox(&cp, "Telnet protocol adjustments",
1541 IDC_BOX_TELNET2, IDC_BOXT_TELNET2);
1542 radioline(&cp, "Handling of OLD_ENVIRON ambiguity:", IDC_EMSTATIC, 2,
1543 "&BSD (commonplace)", IDC_EMBSD,
1544 "R&FC 1408 (unusual)", IDC_EMRFC, NULL);
1545 endbox(&cp);
1546
1547 treeview_insert(&tvfaff, 1, "Telnet");
1548 }
1549 }
1550
1551 /* The SSH panel. Accelerators used: [acgo] rmakwp123bd */
1552 {
1553 struct ctlpos cp;
1554 ctlposinit(&cp, hwnd, 80, 3, 13);
1555 if (dlgtype == 0) {
1556 bartitle(&cp, "Options controlling SSH connections", IDC_TITLE_SSH);
1557 beginbox(&cp, "Data to send to the server",
1558 IDC_BOX_SSH1, IDC_BOXT_SSH1);
1559 multiedit(&cp,
1560 "&Remote command:", IDC_CMDSTATIC, IDC_CMDEDIT, 100,
1561 NULL);
1562 endbox(&cp);
1563 beginbox(&cp, "Authentication options",
1564 IDC_BOX_SSH2, IDC_BOXT_SSH2);
1565 checkbox(&cp, "Atte&mpt TIS or CryptoCard authentication",
1566 IDC_AUTHTIS);
1567 checkbox(&cp, "Allow &agent forwarding", IDC_AGENTFWD);
1568 editbutton(&cp, "Private &key file for authentication:",
1569 IDC_PKSTATIC, IDC_PKEDIT, "Bro&wse...", IDC_PKBUTTON);
1570 endbox(&cp);
1571 beginbox(&cp, "Protocol options",
1572 IDC_BOX_SSH3, IDC_BOXT_SSH3);
1573 checkbox(&cp, "Don't allocate a &pseudo-terminal", IDC_NOPTY);
1574 radioline(&cp, "Preferred SSH protocol version:",
1575 IDC_SSHPROTSTATIC, 2,
1576 "&1", IDC_SSHPROT1, "&2", IDC_SSHPROT2, NULL);
1577 radioline(&cp, "Preferred encryption algorithm:", IDC_CIPHERSTATIC, 3,
1578 "&3DES", IDC_CIPHER3DES,
1579 "&Blowfish", IDC_CIPHERBLOWF,
1580 "&DES", IDC_CIPHERDES, NULL);
1581 endbox(&cp);
1582
1583 treeview_insert(&tvfaff, 1, "SSH");
1584 }
1585 }
1586
1587 init_dlg_ctrls(hwnd);
1588
1589 /*
1590 * Hide all the controls to start with.
1591 */
1592 hide(hwnd, TRUE, controlstartvalue, controlendvalue);
1593
1594 /*
1595 * Put the treeview selection on to the Session panel. This
1596 * should also cause unhiding of the relevant controls.
1597 */
1598 TreeView_SelectItem(treeview, hsession);
1599
1600 /*
1601 * Set focus into the first available control.
1602 */
1603 {
1604 HWND ctl;
1605 ctl = GetDlgItem(hwnd, IDC_HOST);
1606 if (!ctl) ctl = GetDlgItem(hwnd, IDC_CLOSEEXIT);
1607 SetFocus(ctl);
1608 }
1609
1610 SetWindowLong(hwnd, GWL_USERDATA, 1);
1611 return 0;
1612 case WM_LBUTTONUP:
1613 /*
1614 * Button release should trigger WM_OK if there was a
1615 * previous double click on the session list.
1616 */
1617 ReleaseCapture();
1618 if (readytogo)
1619 SendMessage (hwnd, WM_COMMAND, IDOK, 0);
1620 break;
1621 case WM_NOTIFY:
1622 if (LOWORD(wParam) == IDCX_TREEVIEW &&
1623 ((LPNMHDR)lParam)->code == TVN_SELCHANGED) {
1624 HTREEITEM i = TreeView_GetSelection(((LPNMHDR)lParam)->hwndFrom);
1625 TVITEM item;
1626 char buffer[64];
1627 item.hItem = i;
1628 item.pszText = buffer;
1629 item.cchTextMax = sizeof(buffer);
1630 item.mask = TVIF_TEXT;
1631 TreeView_GetItem(((LPNMHDR)lParam)->hwndFrom, &item);
1632 hide(hwnd, TRUE, controlstartvalue, controlendvalue);
1633 if (!strcmp(buffer, "Session"))
1634 hide(hwnd, FALSE, sessionpanelstart, sessionpanelend);
1635 if (!strcmp(buffer, "Keyboard"))
1636 hide(hwnd, FALSE, keyboardpanelstart, keyboardpanelend);
1637 if (!strcmp(buffer, "Terminal"))
1638 hide(hwnd, FALSE, terminalpanelstart, terminalpanelend);
1639 if (!strcmp(buffer, "Window"))
1640 hide(hwnd, FALSE, windowpanelstart, windowpanelend);
1641 if (!strcmp(buffer, "Connection"))
1642 hide(hwnd, FALSE, connectionpanelstart, connectionpanelend);
1643 if (!strcmp(buffer, "Telnet"))
1644 hide(hwnd, FALSE, telnetpanelstart, telnetpanelend);
1645 if (!strcmp(buffer, "SSH"))
1646 hide(hwnd, FALSE, sshpanelstart, sshpanelend);
1647 if (!strcmp(buffer, "Selection"))
1648 hide(hwnd, FALSE, selectionpanelstart, selectionpanelend);
1649 if (!strcmp(buffer, "Colours"))
1650 hide(hwnd, FALSE, colourspanelstart, colourspanelend);
1651 if (!strcmp(buffer, "Translation"))
1652 hide(hwnd, FALSE, translationpanelstart, translationpanelend);
1653
1654 SetFocus (((LPNMHDR)lParam)->hwndFrom); /* ensure focus stays */
1655 return 0;
1656 }
1657 break;
1658 case WM_COMMAND:
1659 /*
1660 * Only process WM_COMMAND once the dialog is fully formed.
1661 */
1662 if (GetWindowLong(hwnd, GWL_USERDATA) == 1) switch (LOWORD(wParam)) {
1663 case IDOK:
1664 if (*cfg.host)
1665 EndDialog (hwnd, 1);
1666 else
1667 MessageBeep (0);
1668 return 0;
1669 case IDCANCEL:
1670 EndDialog (hwnd, 0);
1671 return 0;
1672 case IDC_PROTTELNET:
1673 case IDC_PROTSSH:
1674 case IDC_PROTRAW:
1675 if (HIWORD(wParam) == BN_CLICKED ||
1676 HIWORD(wParam) == BN_DOUBLECLICKED) {
1677 int i = IsDlgButtonChecked (hwnd, IDC_PROTSSH);
1678 int j = IsDlgButtonChecked (hwnd, IDC_PROTTELNET);
1679 cfg.protocol = i ? PROT_SSH : j ? PROT_TELNET : PROT_RAW ;
1680 if ((cfg.protocol == PROT_SSH && cfg.port == 23) ||
1681 (cfg.protocol == PROT_TELNET && cfg.port == 22)) {
1682 cfg.port = i ? 22 : 23;
1683 SetDlgItemInt (hwnd, IDC_PORT, cfg.port, FALSE);
1684 }
1685 }
1686 break;
1687 case IDC_HOST:
1688 if (HIWORD(wParam) == EN_CHANGE)
1689 GetDlgItemText (hwnd, IDC_HOST, cfg.host,
1690 sizeof(cfg.host)-1);
1691 break;
1692 case IDC_PORT:
1693 if (HIWORD(wParam) == EN_CHANGE)
1694 MyGetDlgItemInt (hwnd, IDC_PORT, &cfg.port);
1695 break;
1696 case IDC_SESSEDIT:
1697 if (HIWORD(wParam) == EN_CHANGE) {
1698 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL,
1699 (WPARAM) -1, 0);
1700 GetDlgItemText (hwnd, IDC_SESSEDIT,
1701 savedsession, sizeof(savedsession)-1);
1702 savedsession[sizeof(savedsession)-1] = '\0';
1703 }
1704 break;
1705 case IDC_SESSSAVE:
1706 if (HIWORD(wParam) == BN_CLICKED ||
1707 HIWORD(wParam) == BN_DOUBLECLICKED) {
1708 /*
1709 * Save a session
1710 */
1711 char str[2048];
1712 GetDlgItemText (hwnd, IDC_SESSEDIT, str, sizeof(str)-1);
1713 if (!*str) {
1714 int n = SendDlgItemMessage (hwnd, IDC_SESSLIST,
1715 LB_GETCURSEL, 0, 0);
1716 if (n == LB_ERR) {
1717 MessageBeep(0);
1718 break;
1719 }
1720 strcpy (str, sessions[n]);
1721 }
1722 save_settings (str, !!strcmp(str, "Default Settings"), &cfg);
1723 get_sesslist (FALSE);
1724 get_sesslist (TRUE);
1725 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_RESETCONTENT,
1726 0, 0);
1727 for (i = 0; i < nsessions; i++)
1728 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_ADDSTRING,
1729 0, (LPARAM) (sessions[i]));
1730 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL,
1731 (WPARAM) -1, 0);
1732 }
1733 break;
1734 case IDC_SESSLIST:
1735 case IDC_SESSLOAD:
1736 if (LOWORD(wParam) == IDC_SESSLOAD &&
1737 HIWORD(wParam) != BN_CLICKED &&
1738 HIWORD(wParam) != BN_DOUBLECLICKED)
1739 break;
1740 if (LOWORD(wParam) == IDC_SESSLIST &&
1741 HIWORD(wParam) != LBN_DBLCLK)
1742 break;
1743 {
1744 int n = SendDlgItemMessage (hwnd, IDC_SESSLIST,
1745 LB_GETCURSEL, 0, 0);
1746 if (n == LB_ERR) {
1747 MessageBeep(0);
1748 break;
1749 }
1750 load_settings (sessions[n],
1751 !!strcmp(sessions[n], "Default Settings"),
1752 &cfg);
1753 init_dlg_ctrls(hwnd);
1754 }
1755 if (LOWORD(wParam) == IDC_SESSLIST) {
1756 /*
1757 * A double-click on a saved session should
1758 * actually start the session, not just load it.
1759 * Unless it's Default Settings or some other
1760 * host-less set of saved settings.
1761 */
1762 if (*cfg.host) {
1763 readytogo = TRUE;
1764 SetCapture(hwnd);
1765 }
1766 }
1767 break;
1768 case IDC_SESSDEL:
1769 if (HIWORD(wParam) == BN_CLICKED ||
1770 HIWORD(wParam) == BN_DOUBLECLICKED) {
1771 int n = SendDlgItemMessage (hwnd, IDC_SESSLIST,
1772 LB_GETCURSEL, 0, 0);
1773 if (n == LB_ERR || n == 0) {
1774 MessageBeep(0);
1775 break;
1776 }
1777 del_settings(sessions[n]);
1778 get_sesslist (FALSE);
1779 get_sesslist (TRUE);
1780 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_RESETCONTENT,
1781 0, 0);
1782 for (i = 0; i < nsessions; i++)
1783 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_ADDSTRING,
1784 0, (LPARAM) (sessions[i]));
1785 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL,
1786 (WPARAM) -1, 0);
1787 }
1788 case IDC_PINGEDIT:
1789 if (HIWORD(wParam) == EN_CHANGE)
1790 MyGetDlgItemInt (hwnd, IDC_PINGEDIT, &cfg.ping_interval);
1791 break;
1792 case IDC_DEL008:
1793 case IDC_DEL127:
1794 if (HIWORD(wParam) == BN_CLICKED ||
1795 HIWORD(wParam) == BN_DOUBLECLICKED)
1796 cfg.bksp_is_delete = IsDlgButtonChecked (hwnd, IDC_DEL127);
1797 break;
1798 case IDC_HOMETILDE:
1799 case IDC_HOMERXVT:
1800 if (HIWORD(wParam) == BN_CLICKED ||
1801 HIWORD(wParam) == BN_DOUBLECLICKED)
1802 cfg.rxvt_homeend = IsDlgButtonChecked (hwnd, IDC_HOMERXVT);
1803 break;
1804 case IDC_FUNCXTERM:
1805 if (HIWORD(wParam) == BN_CLICKED ||
1806 HIWORD(wParam) == BN_DOUBLECLICKED)
1807 cfg.funky_type = 2;
1808 break;
1809 case IDC_FUNCVT400:
1810 if (HIWORD(wParam) == BN_CLICKED ||
1811 HIWORD(wParam) == BN_DOUBLECLICKED)
1812 cfg.funky_type = 3;
1813 break;
1814 case IDC_FUNCTILDE:
1815 case IDC_FUNCLINUX:
1816 if (HIWORD(wParam) == BN_CLICKED ||
1817 HIWORD(wParam) == BN_DOUBLECLICKED)
1818 cfg.funky_type = IsDlgButtonChecked (hwnd, IDC_FUNCLINUX);
1819 break;
1820 case IDC_KPNORMAL:
1821 case IDC_KPAPPLIC:
1822 if (HIWORD(wParam) == BN_CLICKED ||
1823 HIWORD(wParam) == BN_DOUBLECLICKED) {
1824 cfg.app_keypad = IsDlgButtonChecked (hwnd, IDC_KPAPPLIC);
1825 cfg.nethack_keypad = FALSE;
1826 }
1827 break;
1828 case IDC_KPNH:
1829 if (HIWORD(wParam) == BN_CLICKED ||
1830 HIWORD(wParam) == BN_DOUBLECLICKED) {
1831 cfg.app_keypad = FALSE;
1832 cfg.nethack_keypad = TRUE;
1833 }
1834 break;
1835 case IDC_CURNORMAL:
1836 case IDC_CURAPPLIC:
1837 if (HIWORD(wParam) == BN_CLICKED ||
1838 HIWORD(wParam) == BN_DOUBLECLICKED)
1839 cfg.app_cursor = IsDlgButtonChecked (hwnd, IDC_CURAPPLIC);
1840 break;
1841 case IDC_ALTF4:
1842 if (HIWORD(wParam) == BN_CLICKED ||
1843 HIWORD(wParam) == BN_DOUBLECLICKED)
1844 cfg.alt_f4 = IsDlgButtonChecked (hwnd, IDC_ALTF4);
1845 break;
1846 case IDC_ALTSPACE:
1847 if (HIWORD(wParam) == BN_CLICKED ||
1848 HIWORD(wParam) == BN_DOUBLECLICKED)
1849 cfg.alt_space = IsDlgButtonChecked (hwnd, IDC_ALTSPACE);
1850 break;
1851 case IDC_LDISCTERM:
1852 if (HIWORD(wParam) == BN_CLICKED ||
1853 HIWORD(wParam) == BN_DOUBLECLICKED)
1854 cfg.ldisc_term = IsDlgButtonChecked (hwnd, IDC_LDISCTERM);
1855 break;
1856 case IDC_SCROLLKEY:
1857 if (HIWORD(wParam) == BN_CLICKED ||
1858 HIWORD(wParam) == BN_DOUBLECLICKED)
1859 cfg.scroll_on_key = IsDlgButtonChecked (hwnd, IDC_SCROLLKEY);
1860 break;
1861 case IDC_WRAPMODE:
1862 if (HIWORD(wParam) == BN_CLICKED ||
1863 HIWORD(wParam) == BN_DOUBLECLICKED)
1864 cfg.wrap_mode = IsDlgButtonChecked (hwnd, IDC_WRAPMODE);
1865 break;
1866 case IDC_DECOM:
1867 if (HIWORD(wParam) == BN_CLICKED ||
1868 HIWORD(wParam) == BN_DOUBLECLICKED)
1869 cfg.dec_om = IsDlgButtonChecked (hwnd, IDC_DECOM);
1870 break;
1871 case IDC_LFHASCR:
1872 if (HIWORD(wParam) == BN_CLICKED ||
1873 HIWORD(wParam) == BN_DOUBLECLICKED)
1874 cfg.lfhascr = IsDlgButtonChecked (hwnd, IDC_LFHASCR);
1875 break;
1876 case IDC_ROWSEDIT:
1877 if (HIWORD(wParam) == EN_CHANGE)
1878 MyGetDlgItemInt (hwnd, IDC_ROWSEDIT, &cfg.height);
1879 break;
1880 case IDC_COLSEDIT:
1881 if (HIWORD(wParam) == EN_CHANGE)
1882 MyGetDlgItemInt (hwnd, IDC_COLSEDIT, &cfg.width);
1883 break;
1884 case IDC_SAVEEDIT:
1885 if (HIWORD(wParam) == EN_CHANGE)
1886 MyGetDlgItemInt (hwnd, IDC_SAVEEDIT, &cfg.savelines);
1887 break;
1888 case IDC_CHOOSEFONT:
1889 lf.lfHeight = cfg.fontheight;
1890 lf.lfWidth = lf.lfEscapement = lf.lfOrientation = 0;
1891 lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = 0;
1892 lf.lfWeight = (cfg.fontisbold ? FW_BOLD : 0);
1893 lf.lfCharSet = cfg.fontcharset;
1894 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
1895 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1896 lf.lfQuality = DEFAULT_QUALITY;
1897 lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
1898 strncpy (lf.lfFaceName, cfg.font, sizeof(lf.lfFaceName)-1);
1899 lf.lfFaceName[sizeof(lf.lfFaceName)-1] = '\0';
1900
1901 cf.lStructSize = sizeof(cf);
1902 cf.hwndOwner = hwnd;
1903 cf.lpLogFont = &lf;
1904 cf.Flags = CF_FIXEDPITCHONLY | CF_FORCEFONTEXIST |
1905 CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
1906
1907 if (ChooseFont (&cf)) {
1908 strncpy (cfg.font, lf.lfFaceName, sizeof(cfg.font)-1);
1909 cfg.font[sizeof(cfg.font)-1] = '\0';
1910 cfg.fontisbold = (lf.lfWeight == FW_BOLD);
1911 cfg.fontcharset = lf.lfCharSet;
1912 cfg.fontheight = lf.lfHeight;
1913 fmtfont (fontstatic);
1914 SetDlgItemText (hwnd, IDC_FONTSTATIC, fontstatic);
1915 }
1916 break;
1917 case IDC_BEEP:
1918 if (HIWORD(wParam) == BN_CLICKED ||
1919 HIWORD(wParam) == BN_DOUBLECLICKED)
1920 cfg.beep = IsDlgButtonChecked (hwnd, IDC_BEEP);
1921 break;
1922 case IDC_BLINKTEXT:
1923 if (HIWORD(wParam) == BN_CLICKED ||
1924 HIWORD(wParam) == BN_DOUBLECLICKED)
1925 cfg.blinktext = IsDlgButtonChecked (hwnd, IDC_BLINKTEXT);
1926 break;
1927 case IDC_BCE:
1928 if (HIWORD(wParam) == BN_CLICKED ||
1929 HIWORD(wParam) == BN_DOUBLECLICKED)
1930 cfg.bce = IsDlgButtonChecked (hwnd, IDC_BCE);
1931 break;
1932 case IDC_WINNAME:
1933 if (HIWORD(wParam) == BN_CLICKED ||
1934 HIWORD(wParam) == BN_DOUBLECLICKED)
1935 cfg.win_name_always = IsDlgButtonChecked (hwnd, IDC_WINNAME);
1936 break;
1937 case IDC_BLINKCUR:
1938 if (HIWORD(wParam) == BN_CLICKED ||
1939 HIWORD(wParam) == BN_DOUBLECLICKED)
1940 cfg.blink_cur = IsDlgButtonChecked (hwnd, IDC_BLINKCUR);
1941 break;
1942 case IDC_SCROLLBAR:
1943 if (HIWORD(wParam) == BN_CLICKED ||
1944 HIWORD(wParam) == BN_DOUBLECLICKED)
1945 cfg.scrollbar = IsDlgButtonChecked (hwnd, IDC_SCROLLBAR);
1946 break;
1947 case IDC_LOCKSIZE:
1948 if (HIWORD(wParam) == BN_CLICKED ||
1949 HIWORD(wParam) == BN_DOUBLECLICKED)
1950 cfg.locksize = IsDlgButtonChecked (hwnd, IDC_LOCKSIZE);
1951 break;
1952 case IDC_WINEDIT:
1953 if (HIWORD(wParam) == EN_CHANGE)
1954 GetDlgItemText (hwnd, IDC_WINEDIT, cfg.wintitle,
1955 sizeof(cfg.wintitle)-1);
1956 break;
1957 case IDC_CLOSEEXIT:
1958 if (HIWORD(wParam) == BN_CLICKED ||
1959 HIWORD(wParam) == BN_DOUBLECLICKED)
1960 cfg.close_on_exit = IsDlgButtonChecked (hwnd, IDC_CLOSEEXIT);
1961 break;
1962 case IDC_CLOSEWARN:
1963 if (HIWORD(wParam) == BN_CLICKED ||
1964 HIWORD(wParam) == BN_DOUBLECLICKED)
1965 cfg.warn_on_close = IsDlgButtonChecked (hwnd, IDC_CLOSEWARN);
1966 break;
1967 case IDC_TTEDIT:
1968 if (HIWORD(wParam) == EN_CHANGE)
1969 GetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype,
1970 sizeof(cfg.termtype)-1);
1971 break;
1972 case IDC_TSEDIT:
1973 if (HIWORD(wParam) == EN_CHANGE)
1974 GetDlgItemText (hwnd, IDC_TSEDIT, cfg.termspeed,
1975 sizeof(cfg.termspeed)-1);
1976 break;
1977 case IDC_LOGEDIT:
1978 if (HIWORD(wParam) == EN_CHANGE)
1979 GetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username,
1980 sizeof(cfg.username)-1);
1981 break;
1982 case IDC_EMBSD:
1983 case IDC_EMRFC:
1984 cfg.rfc_environ = IsDlgButtonChecked (hwnd, IDC_EMRFC);
1985 break;
1986 case IDC_ENVADD:
1987 if (HIWORD(wParam) == BN_CLICKED ||
1988 HIWORD(wParam) == BN_DOUBLECLICKED) {
1989 char str[sizeof(cfg.environmt)];
1990 char *p;
1991 GetDlgItemText (hwnd, IDC_VAREDIT, str, sizeof(str)-1);
1992 if (!*str) {
1993 MessageBeep(0);
1994 break;
1995 }
1996 p = str + strlen(str);
1997 *p++ = '\t';
1998 GetDlgItemText (hwnd, IDC_VALEDIT, p, sizeof(str)-1-(p-str));
1999 if (!*p) {
2000 MessageBeep(0);
2001 break;
2002 }
2003 p = cfg.environmt;
2004 while (*p) {
2005 while (*p) p++;
2006 p++;
2007 }
2008 if ((p-cfg.environmt) + strlen(str) + 2 < sizeof(cfg.environmt)) {
2009 strcpy (p, str);
2010 p[strlen(str)+1] = '\0';
2011 SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_ADDSTRING,
2012 0, (LPARAM)str);
2013 SetDlgItemText (hwnd, IDC_VAREDIT, "");
2014 SetDlgItemText (hwnd, IDC_VALEDIT, "");
2015 } else {
2016 MessageBox(hwnd, "Environment too big", "PuTTY Error",
2017 MB_OK | MB_ICONERROR);
2018 }
2019 }
2020 break;
2021 case IDC_ENVREMOVE:
2022 if (HIWORD(wParam) != BN_CLICKED &&
2023 HIWORD(wParam) != BN_DOUBLECLICKED)
2024 break;
2025 i = SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_GETCURSEL, 0, 0);
2026 if (i == LB_ERR)
2027 MessageBeep (0);
2028 else {
2029 char *p, *q;
2030
2031 SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_DELETESTRING,
2032 i, 0);
2033 p = cfg.environmt;
2034 while (i > 0) {
2035 if (!*p)
2036 goto disaster;
2037 while (*p) p++;
2038 p++;
2039 i--;
2040 }
2041 q = p;
2042 if (!*p)
2043 goto disaster;
2044 while (*p) p++;
2045 p++;
2046 while (*p) {
2047 while (*p)
2048 *q++ = *p++;
2049 *q++ = *p++;
2050 }
2051 *q = '\0';
2052 disaster:;
2053 }
2054 break;
2055 case IDC_NOPTY:
2056 if (HIWORD(wParam) == BN_CLICKED ||
2057 HIWORD(wParam) == BN_DOUBLECLICKED)
2058 cfg.nopty = IsDlgButtonChecked (hwnd, IDC_NOPTY);
2059 break;
2060 case IDC_AGENTFWD:
2061 if (HIWORD(wParam) == BN_CLICKED ||
2062 HIWORD(wParam) == BN_DOUBLECLICKED)
2063 cfg.agentfwd = IsDlgButtonChecked (hwnd, IDC_AGENTFWD);
2064 break;
2065 case IDC_CIPHER3DES:
2066 case IDC_CIPHERBLOWF:
2067 case IDC_CIPHERDES:
2068 if (HIWORD(wParam) == BN_CLICKED ||
2069 HIWORD(wParam) == BN_DOUBLECLICKED) {
2070 if (IsDlgButtonChecked (hwnd, IDC_CIPHER3DES))
2071 cfg.cipher = CIPHER_3DES;
2072 else if (IsDlgButtonChecked (hwnd, IDC_CIPHERBLOWF))
2073 cfg.cipher = CIPHER_BLOWFISH;
2074 else if (IsDlgButtonChecked (hwnd, IDC_CIPHERDES))
2075 cfg.cipher = CIPHER_DES;
2076 }
2077 break;
2078 case IDC_SSHPROT1:
2079 case IDC_SSHPROT2:
2080 if (HIWORD(wParam) == BN_CLICKED ||
2081 HIWORD(wParam) == BN_DOUBLECLICKED) {
2082 if (IsDlgButtonChecked (hwnd, IDC_SSHPROT1))
2083 cfg.sshprot = 1;
2084 else if (IsDlgButtonChecked (hwnd, IDC_SSHPROT2))
2085 cfg.sshprot = 2;
2086 }
2087 break;
2088 case IDC_AUTHTIS:
2089 if (HIWORD(wParam) == BN_CLICKED ||
2090 HIWORD(wParam) == BN_DOUBLECLICKED)
2091 cfg.try_tis_auth = IsDlgButtonChecked (hwnd, IDC_AUTHTIS);
2092 break;
2093 case IDC_PKEDIT:
2094 if (HIWORD(wParam) == EN_CHANGE)
2095 GetDlgItemText (hwnd, IDC_PKEDIT, cfg.keyfile,
2096 sizeof(cfg.keyfile)-1);
2097 break;
2098 case IDC_CMDEDIT:
2099 if (HIWORD(wParam) == EN_CHANGE)
2100 GetDlgItemText (hwnd, IDC_CMDEDIT, cfg.remote_cmd,
2101 sizeof(cfg.remote_cmd)-1);
2102 break;
2103 case IDC_PKBUTTON:
2104 memset(&of, 0, sizeof(of));
2105 #ifdef OPENFILENAME_SIZE_VERSION_400
2106 of.lStructSize = OPENFILENAME_SIZE_VERSION_400;
2107 #else
2108 of.lStructSize = sizeof(of);
2109 #endif
2110 of.hwndOwner = hwnd;
2111 of.lpstrFilter = "All Files\0*\0\0\0";
2112 of.lpstrCustomFilter = NULL;
2113 of.nFilterIndex = 1;
2114 of.lpstrFile = filename; strcpy(filename, cfg.keyfile);
2115 of.nMaxFile = sizeof(filename);
2116 of.lpstrFileTitle = NULL;
2117 of.lpstrInitialDir = NULL;
2118 of.lpstrTitle = "Select Public Key File";
2119 of.Flags = 0;
2120 if (GetOpenFileName(&of)) {
2121 strcpy(cfg.keyfile, filename);
2122 SetDlgItemText (hwnd, IDC_PKEDIT, cfg.keyfile);
2123 }
2124 break;
2125 case IDC_MBWINDOWS:
2126 case IDC_MBXTERM:
2127 cfg.mouse_is_xterm = IsDlgButtonChecked (hwnd, IDC_MBXTERM);
2128 break;
2129 case IDC_CCSET:
2130 {
2131 BOOL ok;
2132 int i;
2133 int n = GetDlgItemInt (hwnd, IDC_CCEDIT, &ok, FALSE);
2134
2135 if (!ok)
2136 MessageBeep (0);
2137 else {
2138 for (i=0; i<256; i++)
2139 if (SendDlgItemMessage (hwnd, IDC_CCLIST, LB_GETSEL,
2140 i, 0)) {
2141 char str[100];
2142 cfg.wordness[i] = n;
2143 SendDlgItemMessage (hwnd, IDC_CCLIST,
2144 LB_DELETESTRING, i, 0);
2145 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
2146 (i>=0x21 && i != 0x7F) ? i : ' ',
2147 cfg.wordness[i]);
2148 SendDlgItemMessage (hwnd, IDC_CCLIST,
2149 LB_INSERTSTRING, i,
2150 (LPARAM)str);
2151 }
2152 }
2153 }
2154 break;
2155 case IDC_BOLDCOLOUR:
2156 if (HIWORD(wParam) == BN_CLICKED ||
2157 HIWORD(wParam) == BN_DOUBLECLICKED) {
2158 int n, i;
2159 cfg.bold_colour = IsDlgButtonChecked (hwnd, IDC_BOLDCOLOUR);
2160 n = SendDlgItemMessage (hwnd, IDC_LIST, LB_GETCOUNT, 0, 0);
2161 if (cfg.bold_colour && n!=22) {
2162 for (i=0; i<22; i++)
2163 if (!permcolour[i])
2164 SendDlgItemMessage (hwnd, IDC_LIST,
2165 LB_INSERTSTRING, i,
2166 (LPARAM) colours[i]);
2167 } else if (!cfg.bold_colour && n!=12) {
2168 for (i=22; i-- ;)
2169 if (!permcolour[i])
2170 SendDlgItemMessage (hwnd, IDC_LIST,
2171 LB_DELETESTRING, i, 0);
2172 }
2173 }
2174 break;
2175 case IDC_PALETTE:
2176 if (HIWORD(wParam) == BN_CLICKED ||
2177 HIWORD(wParam) == BN_DOUBLECLICKED)
2178 cfg.try_palette = IsDlgButtonChecked (hwnd, IDC_PALETTE);
2179 break;
2180 case IDC_LIST:
2181 if (HIWORD(wParam) == LBN_DBLCLK ||
2182 HIWORD(wParam) == LBN_SELCHANGE) {
2183 int i = SendDlgItemMessage (hwnd, IDC_LIST, LB_GETCURSEL,
2184 0, 0);
2185 if (!cfg.bold_colour)
2186 i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
2187 SetDlgItemInt (hwnd, IDC_RVALUE, cfg.colours[i][0], FALSE);
2188 SetDlgItemInt (hwnd, IDC_GVALUE, cfg.colours[i][1], FALSE);
2189 SetDlgItemInt (hwnd, IDC_BVALUE, cfg.colours[i][2], FALSE);
2190 }
2191 break;
2192 case IDC_CHANGE:
2193 if (HIWORD(wParam) == BN_CLICKED ||
2194 HIWORD(wParam) == BN_DOUBLECLICKED) {
2195 static CHOOSECOLOR cc;
2196 static DWORD custom[16] = {0}; /* zero initialisers */
2197 int i = SendDlgItemMessage (hwnd, IDC_LIST, LB_GETCURSEL,
2198 0, 0);
2199 if (!cfg.bold_colour)
2200 i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
2201 cc.lStructSize = sizeof(cc);
2202 cc.hwndOwner = hwnd;
2203 cc.hInstance = (HWND)hinst;
2204 cc.lpCustColors = custom;
2205 cc.rgbResult = RGB (cfg.colours[i][0], cfg.colours[i][1],
2206 cfg.colours[i][2]);
2207 cc.Flags = CC_FULLOPEN | CC_RGBINIT;
2208 if (ChooseColor(&cc)) {
2209 cfg.colours[i][0] =
2210 (unsigned char) (cc.rgbResult & 0xFF);
2211 cfg.colours[i][1] =
2212 (unsigned char) (cc.rgbResult >> 8) & 0xFF;
2213 cfg.colours[i][2] =
2214 (unsigned char) (cc.rgbResult >> 16) & 0xFF;
2215 SetDlgItemInt (hwnd, IDC_RVALUE, cfg.colours[i][0],
2216 FALSE);
2217 SetDlgItemInt (hwnd, IDC_GVALUE, cfg.colours[i][1],
2218 FALSE);
2219 SetDlgItemInt (hwnd, IDC_BVALUE, cfg.colours[i][2],
2220 FALSE);
2221 }
2222 }
2223 break;
2224 case IDC_NOXLAT:
2225 case IDC_KOI8WIN1251:
2226 case IDC_88592WIN1250:
2227 case IDC_88592CP852:
2228 cfg.xlat_enablekoiwin =
2229 IsDlgButtonChecked (hwnd, IDC_KOI8WIN1251);
2230 cfg.xlat_88592w1250 =
2231 IsDlgButtonChecked (hwnd, IDC_88592WIN1250);
2232 cfg.xlat_88592cp852 =
2233 IsDlgButtonChecked (hwnd, IDC_88592CP852);
2234 break;
2235 case IDC_CAPSLOCKCYR:
2236 if (HIWORD(wParam) == BN_CLICKED ||
2237 HIWORD(wParam) == BN_DOUBLECLICKED) {
2238 cfg.xlat_capslockcyr =
2239 IsDlgButtonChecked (hwnd, IDC_CAPSLOCKCYR);
2240 }
2241 break;
2242 case IDC_VTXWINDOWS:
2243 case IDC_VTOEMANSI:
2244 case IDC_VTOEMONLY:
2245 case IDC_VTPOORMAN:
2246 cfg.vtmode =
2247 (IsDlgButtonChecked (hwnd, IDC_VTXWINDOWS) ? VT_XWINDOWS :
2248 IsDlgButtonChecked (hwnd, IDC_VTOEMANSI) ? VT_OEMANSI :
2249 IsDlgButtonChecked (hwnd, IDC_VTOEMONLY) ? VT_OEMONLY :
2250 VT_POORMAN);
2251 break;
2252 }
2253 return 0;
2254 case WM_CLOSE:
2255 EndDialog (hwnd, 0);
2256 return 0;
2257
2258 /* Grrr Explorer will maximize Dialogs! */
2259 case WM_SIZE:
2260 if (wParam == SIZE_MAXIMIZED)
2261 force_normal(hwnd);
2262 return 0;
2263 }
2264 return 0;
2265 }
2266
2267 static int CALLBACK MainDlgProc (HWND hwnd, UINT msg,
2268 WPARAM wParam, LPARAM lParam) {
2269 static HWND page = NULL;
2270
2271 if (msg == WM_COMMAND && LOWORD(wParam) == IDOK) {
2272 }
2273 if (msg == WM_COMMAND && LOWORD(wParam) == IDCX_ABOUT) {
2274 EnableWindow(hwnd, 0);
2275 DialogBox(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
2276 GetParent(hwnd), AboutProc);
2277 EnableWindow(hwnd, 1);
2278 SetActiveWindow(hwnd);
2279 }
2280 return GenericMainDlgProc (hwnd, msg, wParam, lParam, 0);
2281 }
2282
2283 static int CALLBACK ReconfDlgProc (HWND hwnd, UINT msg,
2284 WPARAM wParam, LPARAM lParam) {
2285 static HWND page;
2286 return GenericMainDlgProc (hwnd, msg, wParam, lParam, 1);
2287 }
2288
2289 int do_config (void) {
2290 int ret;
2291
2292 get_sesslist(TRUE);
2293 savedsession[0] = '\0';
2294 ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_MAINBOX), NULL, MainDlgProc);
2295 get_sesslist(FALSE);
2296
2297 return ret;
2298 }
2299
2300 int do_reconfig (HWND hwnd) {
2301 Config backup_cfg;
2302 int ret;
2303
2304 backup_cfg = cfg; /* structure copy */
2305 ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_RECONF), hwnd, ReconfDlgProc);
2306 if (!ret)
2307 cfg = backup_cfg; /* structure copy */
2308 else
2309 force_normal(hwnd);
2310
2311 return ret;
2312 }
2313
2314 void logevent (char *string) {
2315 if (nevents >= negsize) {
2316 negsize += 64;
2317 events = srealloc (events, negsize * sizeof(*events));
2318 }
2319 events[nevents] = smalloc(1+strlen(string));
2320 strcpy (events[nevents], string);
2321 nevents++;
2322 if (logbox) {
2323 int count;
2324 SendDlgItemMessage (logbox, IDN_LIST, LB_ADDSTRING,
2325 0, (LPARAM)string);
2326 count = SendDlgItemMessage (logbox, IDN_LIST, LB_GETCOUNT, 0, 0);
2327 SendDlgItemMessage (logbox, IDN_LIST, LB_SETTOPINDEX, count-1, 0);
2328 }
2329 }
2330
2331 void showeventlog (HWND hwnd) {
2332 if (!logbox) {
2333 logbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_LOGBOX),
2334 hwnd, LogProc);
2335 ShowWindow (logbox, SW_SHOWNORMAL);
2336 }
2337 }
2338
2339 void showabout (HWND hwnd) {
2340 if (!abtbox) {
2341 abtbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
2342 hwnd, AboutProc);
2343 ShowWindow (abtbox, SW_SHOWNORMAL);
2344 }
2345 }
2346
2347 void verify_ssh_host_key(char *host, int port, char *keytype,
2348 char *keystr, char *fingerprint) {
2349 int ret;
2350
2351 static const char absentmsg[] =
2352 "The server's host key is not cached in the registry. You\n"
2353 "have no guarantee that the server is the computer you\n"
2354 "think it is.\n"
2355 "The server's key fingerprint is:\n"
2356 "%s\n"
2357 "If you trust this host, hit Yes to add the key to\n"
2358 "PuTTY's cache and carry on connecting.\n"
2359 "If you do not trust this host, hit No to abandon the\n"
2360 "connection.\n";
2361
2362 static const char wrongmsg[] =
2363 "WARNING - POTENTIAL SECURITY BREACH!\n"
2364 "\n"
2365 "The server's host key does not match the one PuTTY has\n"
2366 "cached in the registry. This means that either the\n"
2367 "server administrator has changed the host key, or you\n"
2368 "have actually connected to another computer pretending\n"
2369 "to be the server.\n"
2370 "The new key fingerprint is:\n"
2371 "%s\n"
2372 "If you were expecting this change and trust the new key,\n"
2373 "hit Yes to update PuTTY's cache and continue connecting.\n"
2374 "If you want to carry on connecting but without updating\n"
2375 "the cache, hit No.\n"
2376 "If you want to abandon the connection completely, hit\n"
2377 "Cancel. Hitting Cancel is the ONLY guaranteed safe\n"
2378 "choice.\n";
2379
2380 static const char mbtitle[] = "PuTTY Security Alert";
2381
2382
2383 char message[160+ /* sensible fingerprint max size */
2384 (sizeof(absentmsg) > sizeof(wrongmsg) ?
2385 sizeof(absentmsg) : sizeof(wrongmsg))];
2386
2387 /*
2388 * Verify the key against the registry.
2389 */
2390 ret = verify_host_key(host, port, keytype, keystr);
2391
2392 if (ret == 0) /* success - key matched OK */
2393 return;
2394 if (ret == 2) { /* key was different */
2395 int mbret;
2396 sprintf(message, wrongmsg, fingerprint);
2397 mbret = MessageBox(NULL, message, mbtitle,
2398 MB_ICONWARNING | MB_YESNOCANCEL);
2399 if (mbret == IDYES)
2400 store_host_key(host, port, keytype, keystr);
2401 if (mbret == IDCANCEL)
2402 exit(0);
2403 }
2404 if (ret == 1) { /* key was absent */
2405 int mbret;
2406 sprintf(message, absentmsg, fingerprint);
2407 mbret = MessageBox(NULL, message, mbtitle,
2408 MB_ICONWARNING | MB_YESNO);
2409 if (mbret == IDNO)
2410 exit(0);
2411 store_host_key(host, port, keytype, keystr);
2412 }
2413 }