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