Stop throwing out the Connection panel during midsession reconfig.
[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 7
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 if (wParam == 0) {
826 multiedit(&cp,
827 "Host &Name", IDC_HOSTSTATIC, IDC_HOST, 75,
828 "&Port", IDC_PORTSTATIC, IDC_PORT, 25, NULL);
829 if (backends[2].backend == NULL) {
830 /* this is PuTTYtel, so only two protocols available */
831 radioline(&cp, "Protocol:", IDC_PROTSTATIC, 3,
832 "&Raw", IDC_PROTRAW,
833 "&Telnet", IDC_PROTTELNET, NULL);
834 } else {
835 radioline(&cp, "Protocol:", IDC_PROTSTATIC, 3,
836 "&Raw", IDC_PROTRAW,
837 "&Telnet", IDC_PROTTELNET,
838 #ifdef FWHACK
839 "SS&H/hack",
840 #else
841 "SS&H",
842 #endif
843 IDC_PROTSSH, NULL);
844 }
845 sesssaver(&cp, "Stor&ed Sessions",
846 IDC_SESSSTATIC, IDC_SESSEDIT, IDC_SESSLIST,
847 "&Load", IDC_SESSLOAD,
848 "&Save", IDC_SESSSAVE,
849 "&Delete", IDC_SESSDEL, NULL);
850 }
851 checkbox(&cp, "Close Window on E&xit", IDC_CLOSEEXIT);
852 checkbox(&cp, "&Warn on Close", IDC_CLOSEWARN);
853
854 SetDlgItemText (hwnd, IDC_HOST, cfg.host);
855 SetDlgItemText (hwnd, IDC_SESSEDIT, savedsession);
856 SetDlgItemInt (hwnd, IDC_PORT, cfg.port, FALSE);
857 for (i = 0; i < nsessions; i++)
858 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_ADDSTRING,
859 0, (LPARAM) (sessions[i]));
860 CheckRadioButton (hwnd, IDC_PROTRAW, IDC_PROTSSH,
861 cfg.protocol==PROT_SSH ? IDC_PROTSSH :
862 cfg.protocol==PROT_TELNET ? IDC_PROTTELNET : IDC_PROTRAW );
863 CheckDlgButton (hwnd, IDC_CLOSEEXIT, cfg.close_on_exit);
864 CheckDlgButton (hwnd, IDC_CLOSEWARN, cfg.warn_on_close);
865 break;
866 case WM_LBUTTONUP:
867 /*
868 * Button release should trigger WM_OK if there was a
869 * previous double click on the session list.
870 */
871 ReleaseCapture();
872 if (readytogo)
873 SendMessage (GetParent(hwnd), WM_COMMAND, IDOK, 0);
874 break;
875 case WM_COMMAND:
876 switch (LOWORD(wParam)) {
877 case IDC_PROTTELNET:
878 case IDC_PROTSSH:
879 case IDC_PROTRAW:
880 if (HIWORD(wParam) == BN_CLICKED ||
881 HIWORD(wParam) == BN_DOUBLECLICKED) {
882 int i = IsDlgButtonChecked (hwnd, IDC_PROTSSH);
883 int j = IsDlgButtonChecked (hwnd, IDC_PROTTELNET);
884 cfg.protocol = i ? PROT_SSH : j ? PROT_TELNET : PROT_RAW ;
885 if ((cfg.protocol == PROT_SSH && cfg.port == 23) ||
886 (cfg.protocol == PROT_TELNET && cfg.port == 22)) {
887 cfg.port = i ? 22 : 23;
888 SetDlgItemInt (hwnd, IDC_PORT, cfg.port, FALSE);
889 }
890 }
891 break;
892 case IDC_HOST:
893 if (HIWORD(wParam) == EN_CHANGE)
894 GetDlgItemText (hwnd, IDC_HOST, cfg.host,
895 sizeof(cfg.host)-1);
896 break;
897 case IDC_PORT:
898 if (HIWORD(wParam) == EN_CHANGE)
899 MyGetDlgItemInt (hwnd, IDC_PORT, &cfg.port);
900 break;
901 case IDC_CLOSEEXIT:
902 if (HIWORD(wParam) == BN_CLICKED ||
903 HIWORD(wParam) == BN_DOUBLECLICKED)
904 cfg.close_on_exit = IsDlgButtonChecked (hwnd, IDC_CLOSEEXIT);
905 break;
906 case IDC_CLOSEWARN:
907 if (HIWORD(wParam) == BN_CLICKED ||
908 HIWORD(wParam) == BN_DOUBLECLICKED)
909 cfg.warn_on_close = IsDlgButtonChecked (hwnd, IDC_CLOSEWARN);
910 break;
911 case IDC_SESSEDIT:
912 if (HIWORD(wParam) == EN_CHANGE) {
913 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL,
914 (WPARAM) -1, 0);
915 GetDlgItemText (hwnd, IDC_SESSEDIT,
916 savedsession, sizeof(savedsession)-1);
917 savedsession[sizeof(savedsession)-1] = '\0';
918 }
919 break;
920 case IDC_SESSSAVE:
921 if (HIWORD(wParam) == BN_CLICKED ||
922 HIWORD(wParam) == BN_DOUBLECLICKED) {
923 /*
924 * Save a session
925 */
926 char str[2048];
927 GetDlgItemText (hwnd, IDC_SESSEDIT, str, sizeof(str)-1);
928 if (!*str) {
929 int n = SendDlgItemMessage (hwnd, IDC_SESSLIST,
930 LB_GETCURSEL, 0, 0);
931 if (n == LB_ERR) {
932 MessageBeep(0);
933 break;
934 }
935 strcpy (str, sessions[n]);
936 }
937 save_settings (str, !!strcmp(str, "Default Settings"), &cfg);
938 get_sesslist (FALSE);
939 get_sesslist (TRUE);
940 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_RESETCONTENT,
941 0, 0);
942 for (i = 0; i < nsessions; i++)
943 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_ADDSTRING,
944 0, (LPARAM) (sessions[i]));
945 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL,
946 (WPARAM) -1, 0);
947 }
948 break;
949 case IDC_SESSLIST:
950 case IDC_SESSLOAD:
951 if (LOWORD(wParam) == IDC_SESSLOAD &&
952 HIWORD(wParam) != BN_CLICKED &&
953 HIWORD(wParam) != BN_DOUBLECLICKED)
954 break;
955 if (LOWORD(wParam) == IDC_SESSLIST &&
956 HIWORD(wParam) != LBN_DBLCLK)
957 break;
958 {
959 int n = SendDlgItemMessage (hwnd, IDC_SESSLIST,
960 LB_GETCURSEL, 0, 0);
961 if (n == LB_ERR) {
962 MessageBeep(0);
963 break;
964 }
965 load_settings (sessions[n],
966 !!strcmp(sessions[n], "Default Settings"),
967 &cfg);
968 SetDlgItemText (hwnd, IDC_HOST, cfg.host);
969 SetDlgItemInt (hwnd, IDC_PORT, cfg.port, FALSE);
970 CheckRadioButton (hwnd, IDC_PROTRAW, IDC_PROTSSH,
971 (cfg.protocol==PROT_SSH ? IDC_PROTSSH :
972 cfg.protocol==PROT_TELNET ? IDC_PROTTELNET : IDC_PROTRAW));
973 CheckDlgButton (hwnd, IDC_CLOSEEXIT, cfg.close_on_exit);
974 CheckDlgButton (hwnd, IDC_CLOSEWARN, cfg.warn_on_close);
975 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL,
976 (WPARAM) -1, 0);
977 }
978 if (LOWORD(wParam) == IDC_SESSLIST) {
979 /*
980 * A double-click on a saved session should
981 * actually start the session, not just load it.
982 * Unless it's Default Settings or some other
983 * host-less set of saved settings.
984 */
985 if (*cfg.host) {
986 readytogo = TRUE;
987 SetCapture(hwnd);
988 }
989 }
990 break;
991 case IDC_SESSDEL:
992 if (HIWORD(wParam) == BN_CLICKED ||
993 HIWORD(wParam) == BN_DOUBLECLICKED) {
994 int n = SendDlgItemMessage (hwnd, IDC_SESSLIST,
995 LB_GETCURSEL, 0, 0);
996 if (n == LB_ERR || n == 0) {
997 MessageBeep(0);
998 break;
999 }
1000 del_settings(sessions[n]);
1001 get_sesslist (FALSE);
1002 get_sesslist (TRUE);
1003 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_RESETCONTENT,
1004 0, 0);
1005 for (i = 0; i < nsessions; i++)
1006 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_ADDSTRING,
1007 0, (LPARAM) (sessions[i]));
1008 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL,
1009 (WPARAM) -1, 0);
1010 }
1011 }
1012 }
1013 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1014 }
1015
1016 static int CALLBACK KeyboardProc (HWND hwnd, UINT msg,
1017 WPARAM wParam, LPARAM lParam) {
1018 struct ctlpos cp;
1019 enum { controlstartvalue = 1000,
1020 IDC_DELSTATIC,
1021 IDC_DEL008,
1022 IDC_DEL127,
1023 IDC_HOMESTATIC,
1024 IDC_HOMETILDE,
1025 IDC_HOMERXVT,
1026 IDC_FUNCSTATIC,
1027 IDC_FUNCTILDE,
1028 IDC_FUNCLINUX,
1029 IDC_FUNCXTERM,
1030 IDC_KPSTATIC,
1031 IDC_KPNORMAL,
1032 IDC_KPAPPLIC,
1033 IDC_KPNH,
1034 IDC_CURSTATIC,
1035 IDC_CURNORMAL,
1036 IDC_CURAPPLIC,
1037 IDC_ALTF4,
1038 IDC_ALTSPACE,
1039 IDC_LDISCTERM,
1040 IDC_SCROLLKEY
1041 };
1042
1043 switch (msg) {
1044 case WM_INITDIALOG:
1045 /* Accelerators used: [aco] 4?ehiklmnprsuvxy */
1046 ctlposinit(&cp, hwnd);
1047 radioline(&cp, "Action of Backspace:", IDC_DELSTATIC, 2,
1048 "Control-&H", IDC_DEL008,
1049 "Control-&? (127)", IDC_DEL127, NULL);
1050 radioline(&cp, "Action of Home and End:", IDC_HOMESTATIC, 2,
1051 "&Standard", IDC_HOMETILDE,
1052 "&rxvt", IDC_HOMERXVT, NULL);
1053 radioline(&cp, "Function key and keypad layout:", IDC_FUNCSTATIC, 3,
1054 "&VT400", IDC_FUNCTILDE,
1055 "&Linux", IDC_FUNCLINUX,
1056 "&Xterm R6", IDC_FUNCXTERM, NULL);
1057 radioline(&cp, "Initial state of cursor keys:", IDC_CURSTATIC, 2,
1058 "&Normal", IDC_CURNORMAL,
1059 "A&pplication", IDC_CURAPPLIC, NULL);
1060 radioline(&cp, "Initial state of numeric keypad:", IDC_KPSTATIC, 3,
1061 "Nor&mal", IDC_KPNORMAL,
1062 "Appl&ication", IDC_KPAPPLIC,
1063 "N&etHack", IDC_KPNH, NULL);
1064 checkbox(&cp, "ALT-F&4 is special (closes window)", IDC_ALTF4);
1065 checkbox(&cp, "ALT-Space is special (S&ystem menu)", IDC_ALTSPACE);
1066 checkbox(&cp, "&Use local terminal line discipline", IDC_LDISCTERM);
1067 checkbox(&cp, "Reset scrollback on &keypress", IDC_SCROLLKEY);
1068
1069 CheckRadioButton (hwnd, IDC_DEL008, IDC_DEL127,
1070 cfg.bksp_is_delete ? IDC_DEL127 : IDC_DEL008);
1071 CheckRadioButton (hwnd, IDC_HOMETILDE, IDC_HOMERXVT,
1072 cfg.rxvt_homeend ? IDC_HOMERXVT : IDC_HOMETILDE);
1073 CheckRadioButton (hwnd, IDC_FUNCTILDE, IDC_FUNCXTERM,
1074 cfg.funky_type ?
1075 (cfg.funky_type==2 ? IDC_FUNCXTERM
1076 : IDC_FUNCLINUX )
1077 : IDC_FUNCTILDE);
1078 CheckRadioButton (hwnd, IDC_CURNORMAL, IDC_CURAPPLIC,
1079 cfg.app_cursor ? IDC_CURAPPLIC : IDC_CURNORMAL);
1080 CheckRadioButton (hwnd, IDC_KPNORMAL, IDC_KPNH,
1081 cfg.nethack_keypad ? IDC_KPNH :
1082 cfg.app_keypad ? IDC_KPAPPLIC : IDC_KPNORMAL);
1083 CheckDlgButton (hwnd, IDC_ALTF4, cfg.alt_f4);
1084 CheckDlgButton (hwnd, IDC_ALTSPACE, cfg.alt_space);
1085 CheckDlgButton (hwnd, IDC_LDISCTERM, cfg.ldisc_term);
1086 CheckDlgButton (hwnd, IDC_SCROLLKEY, cfg.scroll_on_key);
1087 break;
1088 case WM_COMMAND:
1089 if (HIWORD(wParam) == BN_CLICKED ||
1090 HIWORD(wParam) == BN_DOUBLECLICKED)
1091 switch (LOWORD(wParam)) {
1092 case IDC_DEL008:
1093 case IDC_DEL127:
1094 cfg.bksp_is_delete = IsDlgButtonChecked (hwnd, IDC_DEL127);
1095 break;
1096 case IDC_HOMETILDE:
1097 case IDC_HOMERXVT:
1098 cfg.rxvt_homeend = IsDlgButtonChecked (hwnd, IDC_HOMERXVT);
1099 break;
1100 case IDC_FUNCXTERM:
1101 cfg.funky_type = 2;
1102 break;
1103 case IDC_FUNCTILDE:
1104 case IDC_FUNCLINUX:
1105 cfg.funky_type = IsDlgButtonChecked (hwnd, IDC_FUNCLINUX);
1106 break;
1107 case IDC_KPNORMAL:
1108 case IDC_KPAPPLIC:
1109 cfg.app_keypad = IsDlgButtonChecked (hwnd, IDC_KPAPPLIC);
1110 cfg.nethack_keypad = FALSE;
1111 break;
1112 case IDC_KPNH:
1113 cfg.app_keypad = FALSE;
1114 cfg.nethack_keypad = TRUE;
1115 break;
1116 case IDC_CURNORMAL:
1117 case IDC_CURAPPLIC:
1118 cfg.app_cursor = IsDlgButtonChecked (hwnd, IDC_CURAPPLIC);
1119 break;
1120 case IDC_ALTF4:
1121 if (HIWORD(wParam) == BN_CLICKED ||
1122 HIWORD(wParam) == BN_DOUBLECLICKED)
1123 cfg.alt_f4 = IsDlgButtonChecked (hwnd, IDC_ALTF4);
1124 break;
1125 case IDC_ALTSPACE:
1126 if (HIWORD(wParam) == BN_CLICKED ||
1127 HIWORD(wParam) == BN_DOUBLECLICKED)
1128 cfg.alt_space = IsDlgButtonChecked (hwnd, IDC_ALTSPACE);
1129 break;
1130 case IDC_LDISCTERM:
1131 if (HIWORD(wParam) == BN_CLICKED ||
1132 HIWORD(wParam) == BN_DOUBLECLICKED)
1133 cfg.ldisc_term = IsDlgButtonChecked (hwnd, IDC_LDISCTERM);
1134 break;
1135 case IDC_SCROLLKEY:
1136 if (HIWORD(wParam) == BN_CLICKED ||
1137 HIWORD(wParam) == BN_DOUBLECLICKED)
1138 cfg.scroll_on_key = IsDlgButtonChecked (hwnd, IDC_SCROLLKEY);
1139 break;
1140 }
1141 }
1142 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1143 }
1144
1145 static void fmtfont (char *buf) {
1146 sprintf (buf, "Font: %s, ", cfg.font);
1147 if (cfg.fontisbold)
1148 strcat(buf, "bold, ");
1149 if (cfg.fontheight == 0)
1150 strcat (buf, "default height");
1151 else
1152 sprintf (buf+strlen(buf), "%d-%s",
1153 (cfg.fontheight < 0 ? -cfg.fontheight : cfg.fontheight),
1154 (cfg.fontheight < 0 ? "pixel" : "point"));
1155 }
1156
1157 static int CALLBACK TerminalProc (HWND hwnd, UINT msg,
1158 WPARAM wParam, LPARAM lParam) {
1159 struct ctlpos cp;
1160 CHOOSEFONT cf;
1161 LOGFONT lf;
1162 char fontstatic[256];
1163 enum { controlstartvalue = 1000,
1164 IDC_WRAPMODE,
1165 IDC_DECOM,
1166 IDC_DIMSTATIC,
1167 IDC_ROWSSTATIC,
1168 IDC_ROWSEDIT,
1169 IDC_COLSSTATIC,
1170 IDC_COLSEDIT,
1171 IDC_SAVESTATIC,
1172 IDC_SAVEEDIT,
1173 IDC_FONTSTATIC,
1174 IDC_CHOOSEFONT,
1175 IDC_LFHASCR,
1176 IDC_BEEP,
1177 IDC_BCE,
1178 IDC_BLINKTEXT
1179 };
1180
1181 switch (msg) {
1182 case WM_INITDIALOG:
1183 /* Accelerators used: [aco] dghlmnprsw */
1184 ctlposinit(&cp, hwnd);
1185 multiedit(&cp,
1186 "&Rows", IDC_ROWSSTATIC, IDC_ROWSEDIT, 33,
1187 "Colu&mns", IDC_COLSSTATIC, IDC_COLSEDIT, 33,
1188 "&Scrollback", IDC_SAVESTATIC, IDC_SAVEEDIT, 33,
1189 NULL);
1190 staticbtn(&cp, "", IDC_FONTSTATIC, "C&hange...", IDC_CHOOSEFONT);
1191 checkbox(&cp, "Auto &wrap mode initially on", IDC_WRAPMODE);
1192 checkbox(&cp, "&DEC Origin Mode initially on", IDC_DECOM);
1193 checkbox(&cp, "Implicit CR in every &LF", IDC_LFHASCR);
1194 checkbox(&cp, "Bee&p enabled", IDC_BEEP);
1195 checkbox(&cp, "Use Back&ground colour erase", IDC_BCE);
1196 checkbox(&cp, "Enable bli&nking text", IDC_BLINKTEXT);
1197
1198 CheckDlgButton (hwnd, IDC_WRAPMODE, cfg.wrap_mode);
1199 CheckDlgButton (hwnd, IDC_DECOM, cfg.dec_om);
1200 CheckDlgButton (hwnd, IDC_LFHASCR, cfg.lfhascr);
1201 SetDlgItemInt (hwnd, IDC_ROWSEDIT, cfg.height, FALSE);
1202 SetDlgItemInt (hwnd, IDC_COLSEDIT, cfg.width, FALSE);
1203 SetDlgItemInt (hwnd, IDC_SAVEEDIT, cfg.savelines, FALSE);
1204 fmtfont (fontstatic);
1205 SetDlgItemText (hwnd, IDC_FONTSTATIC, fontstatic);
1206 CheckDlgButton (hwnd, IDC_BEEP, cfg.beep);
1207 CheckDlgButton (hwnd, IDC_BCE, cfg.bce);
1208 CheckDlgButton (hwnd, IDC_BLINKTEXT, cfg.blinktext);
1209 break;
1210 case WM_COMMAND:
1211 switch (LOWORD(wParam)) {
1212 case IDC_WRAPMODE:
1213 if (HIWORD(wParam) == BN_CLICKED ||
1214 HIWORD(wParam) == BN_DOUBLECLICKED)
1215 cfg.wrap_mode = IsDlgButtonChecked (hwnd, IDC_WRAPMODE);
1216 break;
1217 case IDC_DECOM:
1218 if (HIWORD(wParam) == BN_CLICKED ||
1219 HIWORD(wParam) == BN_DOUBLECLICKED)
1220 cfg.dec_om = IsDlgButtonChecked (hwnd, IDC_DECOM);
1221 break;
1222 case IDC_LFHASCR:
1223 if (HIWORD(wParam) == BN_CLICKED ||
1224 HIWORD(wParam) == BN_DOUBLECLICKED)
1225 cfg.lfhascr = IsDlgButtonChecked (hwnd, IDC_LFHASCR);
1226 break;
1227 case IDC_ROWSEDIT:
1228 if (HIWORD(wParam) == EN_CHANGE)
1229 MyGetDlgItemInt (hwnd, IDC_ROWSEDIT, &cfg.height);
1230 break;
1231 case IDC_COLSEDIT:
1232 if (HIWORD(wParam) == EN_CHANGE)
1233 MyGetDlgItemInt (hwnd, IDC_COLSEDIT, &cfg.width);
1234 break;
1235 case IDC_SAVEEDIT:
1236 if (HIWORD(wParam) == EN_CHANGE)
1237 MyGetDlgItemInt (hwnd, IDC_SAVEEDIT, &cfg.savelines);
1238 break;
1239 case IDC_CHOOSEFONT:
1240 lf.lfHeight = cfg.fontheight;
1241 lf.lfWidth = lf.lfEscapement = lf.lfOrientation = 0;
1242 lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = 0;
1243 lf.lfWeight = (cfg.fontisbold ? FW_BOLD : 0);
1244 lf.lfCharSet = cfg.fontcharset;
1245 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
1246 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1247 lf.lfQuality = DEFAULT_QUALITY;
1248 lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
1249 strncpy (lf.lfFaceName, cfg.font, sizeof(lf.lfFaceName)-1);
1250 lf.lfFaceName[sizeof(lf.lfFaceName)-1] = '\0';
1251
1252 cf.lStructSize = sizeof(cf);
1253 cf.hwndOwner = hwnd;
1254 cf.lpLogFont = &lf;
1255 cf.Flags = CF_FIXEDPITCHONLY | CF_FORCEFONTEXIST |
1256 CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
1257
1258 if (ChooseFont (&cf)) {
1259 strncpy (cfg.font, lf.lfFaceName, sizeof(cfg.font)-1);
1260 cfg.font[sizeof(cfg.font)-1] = '\0';
1261 cfg.fontisbold = (lf.lfWeight == FW_BOLD);
1262 cfg.fontcharset = lf.lfCharSet;
1263 cfg.fontheight = lf.lfHeight;
1264 fmtfont (fontstatic);
1265 SetDlgItemText (hwnd, IDC_FONTSTATIC, fontstatic);
1266 }
1267 break;
1268 case IDC_BEEP:
1269 if (HIWORD(wParam) == BN_CLICKED ||
1270 HIWORD(wParam) == BN_DOUBLECLICKED)
1271 cfg.beep = IsDlgButtonChecked (hwnd, IDC_BEEP);
1272 break;
1273 case IDC_BLINKTEXT:
1274 if (HIWORD(wParam) == BN_CLICKED ||
1275 HIWORD(wParam) == BN_DOUBLECLICKED)
1276 cfg.blinktext = IsDlgButtonChecked (hwnd, IDC_BLINKTEXT);
1277 break;
1278 case IDC_BCE:
1279 if (HIWORD(wParam) == BN_CLICKED ||
1280 HIWORD(wParam) == BN_DOUBLECLICKED)
1281 cfg.bce = IsDlgButtonChecked (hwnd, IDC_BCE);
1282 break;
1283 }
1284 break;
1285 }
1286 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1287 }
1288
1289 static int CALLBACK WindowProc (HWND hwnd, UINT msg,
1290 WPARAM wParam, LPARAM lParam) {
1291 struct ctlpos cp;
1292 enum { controlstartvalue = 1000,
1293 IDC_WINNAME,
1294 IDC_BLINKCUR,
1295 IDC_SCROLLBAR,
1296 IDC_LOCKSIZE,
1297 IDC_WINTITLE,
1298 IDC_WINEDIT
1299 };
1300
1301 switch (msg) {
1302 case WM_INITDIALOG:
1303 /* Accelerators used: [aco] bikty */
1304 ctlposinit(&cp, hwnd);
1305 if (wParam == 0)
1306 multiedit(&cp,
1307 "Initial window &title:", IDC_WINTITLE, IDC_WINEDIT, 100,
1308 NULL);
1309 checkbox(&cp, "Avoid ever using &icon title", IDC_WINNAME);
1310 checkbox(&cp, "&Blinking cursor", IDC_BLINKCUR);
1311 checkbox(&cp, "Displa&y scrollbar", IDC_SCROLLBAR);
1312 checkbox(&cp, "Loc&k Window size", IDC_LOCKSIZE);
1313
1314 SetDlgItemText (hwnd, IDC_WINEDIT, cfg.wintitle);
1315 CheckDlgButton (hwnd, IDC_WINNAME, cfg.win_name_always);
1316 CheckDlgButton (hwnd, IDC_BLINKCUR, cfg.blink_cur);
1317 CheckDlgButton (hwnd, IDC_SCROLLBAR, cfg.scrollbar);
1318 CheckDlgButton (hwnd, IDC_LOCKSIZE, cfg.locksize);
1319 break;
1320 case WM_COMMAND:
1321 switch (LOWORD(wParam)) {
1322 case IDC_WINNAME:
1323 if (HIWORD(wParam) == BN_CLICKED ||
1324 HIWORD(wParam) == BN_DOUBLECLICKED)
1325 cfg.win_name_always = IsDlgButtonChecked (hwnd, IDC_WINNAME);
1326 break;
1327 case IDC_BLINKCUR:
1328 if (HIWORD(wParam) == BN_CLICKED ||
1329 HIWORD(wParam) == BN_DOUBLECLICKED)
1330 cfg.blink_cur = IsDlgButtonChecked (hwnd, IDC_BLINKCUR);
1331 break;
1332 case IDC_SCROLLBAR:
1333 if (HIWORD(wParam) == BN_CLICKED ||
1334 HIWORD(wParam) == BN_DOUBLECLICKED)
1335 cfg.scrollbar = IsDlgButtonChecked (hwnd, IDC_SCROLLBAR);
1336 break;
1337 case IDC_LOCKSIZE:
1338 if (HIWORD(wParam) == BN_CLICKED ||
1339 HIWORD(wParam) == BN_DOUBLECLICKED)
1340 cfg.locksize = IsDlgButtonChecked (hwnd, IDC_LOCKSIZE);
1341 break;
1342 case IDC_WINEDIT:
1343 if (HIWORD(wParam) == EN_CHANGE)
1344 GetDlgItemText (hwnd, IDC_WINEDIT, cfg.wintitle,
1345 sizeof(cfg.wintitle)-1);
1346 break;
1347 }
1348 break;
1349 }
1350 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1351 }
1352
1353 static int CALLBACK TelnetProc (HWND hwnd, UINT msg,
1354 WPARAM wParam, LPARAM lParam) {
1355 int i;
1356 struct ctlpos cp;
1357 enum { controlstartvalue = 1000,
1358 IDC_TTSTATIC,
1359 IDC_TTEDIT,
1360 IDC_TSSTATIC,
1361 IDC_TSEDIT,
1362 IDC_LOGSTATIC,
1363 IDC_LOGEDIT,
1364 IDC_ENVSTATIC,
1365 IDC_VARSTATIC,
1366 IDC_VAREDIT,
1367 IDC_VALSTATIC,
1368 IDC_VALEDIT,
1369 IDC_ENVLIST,
1370 IDC_ENVADD,
1371 IDC_ENVREMOVE,
1372 IDC_EMSTATIC,
1373 IDC_EMBSD,
1374 IDC_EMRFC
1375 };
1376
1377 switch (msg) {
1378 case WM_INITDIALOG:
1379 /* Accelerators used: [aco] bdflrstuv */
1380 ctlposinit(&cp, hwnd);
1381 if (wParam == 0) {
1382 staticedit(&cp, "Terminal-&type string", IDC_TTSTATIC, IDC_TTEDIT);
1383 staticedit(&cp, "Terminal-&speed string", IDC_TSSTATIC, IDC_TSEDIT);
1384 staticedit(&cp, "Auto-login &username", IDC_LOGSTATIC, IDC_LOGEDIT);
1385 envsetter(&cp, "Environment variables:", IDC_ENVSTATIC,
1386 "&Variable", IDC_VARSTATIC, IDC_VAREDIT,
1387 "Va&lue", IDC_VALSTATIC, IDC_VALEDIT,
1388 IDC_ENVLIST,
1389 "A&dd", IDC_ENVADD, "&Remove", IDC_ENVREMOVE);
1390 radioline(&cp, "Handling of OLD_ENVIRON ambiguity:", IDC_EMSTATIC, 2,
1391 "&BSD (commonplace)", IDC_EMBSD,
1392 "R&FC 1408 (unusual)", IDC_EMRFC, NULL);
1393 }
1394
1395 SetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype);
1396 SetDlgItemText (hwnd, IDC_TSEDIT, cfg.termspeed);
1397 SetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username);
1398 {
1399 char *p = cfg.environmt;
1400 while (*p) {
1401 SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_ADDSTRING, 0,
1402 (LPARAM) p);
1403 p += strlen(p)+1;
1404 }
1405 }
1406 CheckRadioButton (hwnd, IDC_EMBSD, IDC_EMRFC,
1407 cfg.rfc_environ ? IDC_EMRFC : IDC_EMBSD);
1408 break;
1409 case WM_COMMAND:
1410 switch (LOWORD(wParam)) {
1411 case IDC_TTEDIT:
1412 if (HIWORD(wParam) == EN_CHANGE)
1413 GetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype,
1414 sizeof(cfg.termtype)-1);
1415 break;
1416 case IDC_TSEDIT:
1417 if (HIWORD(wParam) == EN_CHANGE)
1418 GetDlgItemText (hwnd, IDC_TSEDIT, cfg.termspeed,
1419 sizeof(cfg.termspeed)-1);
1420 break;
1421 case IDC_LOGEDIT:
1422 if (HIWORD(wParam) == EN_CHANGE)
1423 GetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username,
1424 sizeof(cfg.username)-1);
1425 break;
1426 case IDC_EMBSD:
1427 case IDC_EMRFC:
1428 cfg.rfc_environ = IsDlgButtonChecked (hwnd, IDC_EMRFC);
1429 break;
1430 case IDC_ENVADD:
1431 if (HIWORD(wParam) == BN_CLICKED ||
1432 HIWORD(wParam) == BN_DOUBLECLICKED) {
1433 char str[sizeof(cfg.environmt)];
1434 char *p;
1435 GetDlgItemText (hwnd, IDC_VAREDIT, str, sizeof(str)-1);
1436 if (!*str) {
1437 MessageBeep(0);
1438 break;
1439 }
1440 p = str + strlen(str);
1441 *p++ = '\t';
1442 GetDlgItemText (hwnd, IDC_VALEDIT, p, sizeof(str)-1-(p-str));
1443 if (!*p) {
1444 MessageBeep(0);
1445 break;
1446 }
1447 p = cfg.environmt;
1448 while (*p) {
1449 while (*p) p++;
1450 p++;
1451 }
1452 if ((p-cfg.environmt) + strlen(str) + 2 < sizeof(cfg.environmt)) {
1453 strcpy (p, str);
1454 p[strlen(str)+1] = '\0';
1455 SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_ADDSTRING,
1456 0, (LPARAM)str);
1457 SetDlgItemText (hwnd, IDC_VAREDIT, "");
1458 SetDlgItemText (hwnd, IDC_VALEDIT, "");
1459 } else {
1460 MessageBox(hwnd, "Environment too big", "PuTTY Error",
1461 MB_OK | MB_ICONERROR);
1462 }
1463 }
1464 break;
1465 case IDC_ENVREMOVE:
1466 if (HIWORD(wParam) != BN_CLICKED &&
1467 HIWORD(wParam) != BN_DOUBLECLICKED)
1468 break;
1469 i = SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_GETCURSEL, 0, 0);
1470 if (i == LB_ERR)
1471 MessageBeep (0);
1472 else {
1473 char *p, *q;
1474
1475 SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_DELETESTRING,
1476 i, 0);
1477 p = cfg.environmt;
1478 while (i > 0) {
1479 if (!*p)
1480 goto disaster;
1481 while (*p) p++;
1482 p++;
1483 i--;
1484 }
1485 q = p;
1486 if (!*p)
1487 goto disaster;
1488 while (*p) p++;
1489 p++;
1490 while (*p) {
1491 while (*p)
1492 *q++ = *p++;
1493 *q++ = *p++;
1494 }
1495 *q = '\0';
1496 disaster:;
1497 }
1498 break;
1499 }
1500 break;
1501 }
1502 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1503 }
1504
1505 static int CALLBACK SshProc (HWND hwnd, UINT msg,
1506 WPARAM wParam, LPARAM lParam) {
1507 struct ctlpos cp;
1508 OPENFILENAME of;
1509 char filename[sizeof(cfg.keyfile)];
1510 enum { controlstartvalue = 1000,
1511 IDC_TTSTATIC,
1512 IDC_TTEDIT,
1513 IDC_LOGSTATIC,
1514 IDC_LOGEDIT,
1515 IDC_NOPTY,
1516 IDC_CIPHERSTATIC,
1517 IDC_CIPHER3DES,
1518 IDC_CIPHERBLOWF,
1519 IDC_CIPHERDES,
1520 IDC_AUTHTIS,
1521 IDC_PKSTATIC,
1522 IDC_PKEDIT,
1523 IDC_PKBUTTON,
1524 IDC_SSHPROTSTATIC,
1525 IDC_SSHPROT1,
1526 IDC_SSHPROT2,
1527 IDC_AGENTFWD,
1528 IDC_CMDSTATIC,
1529 IDC_CMDEDIT
1530 };
1531
1532 switch (msg) {
1533 case WM_INITDIALOG:
1534 /* Accelerators used: [aco] 123abdkmprtuw */
1535 ctlposinit(&cp, hwnd);
1536 if (wParam == 0) {
1537 staticedit(&cp, "Terminal-&type string", IDC_TTSTATIC, IDC_TTEDIT);
1538 staticedit(&cp, "Auto-login &username", IDC_LOGSTATIC, IDC_LOGEDIT);
1539 multiedit(&cp,
1540 "&Remote command:", IDC_CMDSTATIC, IDC_CMDEDIT, 100,
1541 NULL);
1542 checkbox(&cp, "Don't allocate a &pseudo-terminal", IDC_NOPTY);
1543 checkbox(&cp, "Atte&mpt TIS or CryptoCard authentication",
1544 IDC_AUTHTIS);
1545 checkbox(&cp, "Allow &agent forwarding", IDC_AGENTFWD);
1546 editbutton(&cp, "Private &key file for authentication:",
1547 IDC_PKSTATIC, IDC_PKEDIT, "Bro&wse...", IDC_PKBUTTON);
1548 radioline(&cp, "Preferred SSH protocol version:",
1549 IDC_SSHPROTSTATIC, 2,
1550 "&1", IDC_SSHPROT1, "&2", IDC_SSHPROT2, NULL);
1551 radioline(&cp, "Preferred encryption algorithm:", IDC_CIPHERSTATIC, 3,
1552 "&3DES", IDC_CIPHER3DES,
1553 "&Blowfish", IDC_CIPHERBLOWF,
1554 "&DES", IDC_CIPHERDES, NULL);
1555 }
1556
1557 SetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype);
1558 SetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username);
1559 CheckDlgButton (hwnd, IDC_NOPTY, cfg.nopty);
1560 CheckDlgButton (hwnd, IDC_AGENTFWD, cfg.agentfwd);
1561 CheckRadioButton (hwnd, IDC_CIPHER3DES, IDC_CIPHERDES,
1562 cfg.cipher == CIPHER_BLOWFISH ? IDC_CIPHERBLOWF :
1563 cfg.cipher == CIPHER_DES ? IDC_CIPHERDES :
1564 IDC_CIPHER3DES);
1565 CheckRadioButton (hwnd, IDC_SSHPROT1, IDC_SSHPROT2,
1566 cfg.sshprot == 1 ? IDC_SSHPROT1 : IDC_SSHPROT2);
1567 CheckDlgButton (hwnd, IDC_AUTHTIS, cfg.try_tis_auth);
1568 SetDlgItemText (hwnd, IDC_PKEDIT, cfg.keyfile);
1569 SetDlgItemText (hwnd, IDC_CMDEDIT, cfg.remote_cmd);
1570 break;
1571 case WM_COMMAND:
1572 switch (LOWORD(wParam)) {
1573 case IDC_TTEDIT:
1574 if (HIWORD(wParam) == EN_CHANGE)
1575 GetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype,
1576 sizeof(cfg.termtype)-1);
1577 break;
1578 case IDC_LOGEDIT:
1579 if (HIWORD(wParam) == EN_CHANGE)
1580 GetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username,
1581 sizeof(cfg.username)-1);
1582 break;
1583 case IDC_NOPTY:
1584 if (HIWORD(wParam) == BN_CLICKED ||
1585 HIWORD(wParam) == BN_DOUBLECLICKED)
1586 cfg.nopty = IsDlgButtonChecked (hwnd, IDC_NOPTY);
1587 break;
1588 case IDC_AGENTFWD:
1589 if (HIWORD(wParam) == BN_CLICKED ||
1590 HIWORD(wParam) == BN_DOUBLECLICKED)
1591 cfg.agentfwd = IsDlgButtonChecked (hwnd, IDC_AGENTFWD);
1592 break;
1593 case IDC_CIPHER3DES:
1594 case IDC_CIPHERBLOWF:
1595 case IDC_CIPHERDES:
1596 if (HIWORD(wParam) == BN_CLICKED ||
1597 HIWORD(wParam) == BN_DOUBLECLICKED) {
1598 if (IsDlgButtonChecked (hwnd, IDC_CIPHER3DES))
1599 cfg.cipher = CIPHER_3DES;
1600 else if (IsDlgButtonChecked (hwnd, IDC_CIPHERBLOWF))
1601 cfg.cipher = CIPHER_BLOWFISH;
1602 else if (IsDlgButtonChecked (hwnd, IDC_CIPHERDES))
1603 cfg.cipher = CIPHER_DES;
1604 }
1605 break;
1606 case IDC_SSHPROT1:
1607 case IDC_SSHPROT2:
1608 if (HIWORD(wParam) == BN_CLICKED ||
1609 HIWORD(wParam) == BN_DOUBLECLICKED) {
1610 if (IsDlgButtonChecked (hwnd, IDC_SSHPROT1))
1611 cfg.sshprot = 1;
1612 else if (IsDlgButtonChecked (hwnd, IDC_SSHPROT2))
1613 cfg.sshprot = 2;
1614 }
1615 break;
1616 case IDC_AUTHTIS:
1617 if (HIWORD(wParam) == BN_CLICKED ||
1618 HIWORD(wParam) == BN_DOUBLECLICKED)
1619 cfg.try_tis_auth = IsDlgButtonChecked (hwnd, IDC_AUTHTIS);
1620 break;
1621 case IDC_PKEDIT:
1622 if (HIWORD(wParam) == EN_CHANGE)
1623 GetDlgItemText (hwnd, IDC_PKEDIT, cfg.keyfile,
1624 sizeof(cfg.keyfile)-1);
1625 break;
1626 case IDC_CMDEDIT:
1627 if (HIWORD(wParam) == EN_CHANGE)
1628 GetDlgItemText (hwnd, IDC_CMDEDIT, cfg.remote_cmd,
1629 sizeof(cfg.remote_cmd)-1);
1630 break;
1631 case IDC_PKBUTTON:
1632 /*
1633 * FIXME: this crashes. Find out why.
1634 */
1635 memset(&of, 0, sizeof(of));
1636 #ifdef OPENFILENAME_SIZE_VERSION_400
1637 of.lStructSize = OPENFILENAME_SIZE_VERSION_400;
1638 #else
1639 of.lStructSize = sizeof(of);
1640 #endif
1641 of.hwndOwner = hwnd;
1642 of.lpstrFilter = "All Files\0*\0\0\0";
1643 of.lpstrCustomFilter = NULL;
1644 of.nFilterIndex = 1;
1645 of.lpstrFile = filename; strcpy(filename, cfg.keyfile);
1646 of.nMaxFile = sizeof(filename);
1647 of.lpstrFileTitle = NULL;
1648 of.lpstrInitialDir = NULL;
1649 of.lpstrTitle = "Select Public Key File";
1650 of.Flags = 0;
1651 if (GetOpenFileName(&of)) {
1652 strcpy(cfg.keyfile, filename);
1653 SetDlgItemText (hwnd, IDC_PKEDIT, cfg.keyfile);
1654 }
1655 break;
1656 }
1657 break;
1658 }
1659 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1660 }
1661
1662 static int CALLBACK SelectionProc (HWND hwnd, UINT msg,
1663 WPARAM wParam, LPARAM lParam) {
1664 struct ctlpos cp;
1665 int i;
1666 enum { controlstartvalue = 1000,
1667 IDC_MBSTATIC,
1668 IDC_MBWINDOWS,
1669 IDC_MBXTERM,
1670 IDC_CCSTATIC,
1671 IDC_CCLIST,
1672 IDC_CCSET,
1673 IDC_CCSTATIC2,
1674 IDC_CCEDIT
1675 };
1676
1677 switch (msg) {
1678 case WM_INITDIALOG:
1679 /* Accelerators used: [aco] stwx */
1680 ctlposinit(&cp, hwnd);
1681 radiobig(&cp, "Action of mouse buttons:", IDC_MBSTATIC,
1682 "&Windows (Right pastes, Middle extends)", IDC_MBWINDOWS,
1683 "&xterm (Right extends, Middle pastes)", IDC_MBXTERM,
1684 NULL);
1685 charclass(&cp, "Character classes:", IDC_CCSTATIC, IDC_CCLIST,
1686 "&Set", IDC_CCSET, IDC_CCEDIT,
1687 "&to class", IDC_CCSTATIC2);
1688
1689 CheckRadioButton (hwnd, IDC_MBWINDOWS, IDC_MBXTERM,
1690 cfg.mouse_is_xterm ? IDC_MBXTERM : IDC_MBWINDOWS);
1691 {
1692 static int tabs[4] = {25, 61, 96, 128};
1693 SendDlgItemMessage (hwnd, IDC_CCLIST, LB_SETTABSTOPS, 4,
1694 (LPARAM) tabs);
1695 }
1696 for (i=0; i<256; i++) {
1697 char str[100];
1698 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
1699 (i>=0x21 && i != 0x7F) ? i : ' ',
1700 cfg.wordness[i]);
1701 SendDlgItemMessage (hwnd, IDC_CCLIST, LB_ADDSTRING, 0,
1702 (LPARAM) str);
1703 }
1704 break;
1705 case WM_COMMAND:
1706 switch (LOWORD(wParam)) {
1707 case IDC_MBWINDOWS:
1708 case IDC_MBXTERM:
1709 cfg.mouse_is_xterm = IsDlgButtonChecked (hwnd, IDC_MBXTERM);
1710 break;
1711 case IDC_CCSET:
1712 {
1713 BOOL ok;
1714 int i;
1715 int n = GetDlgItemInt (hwnd, IDC_CCEDIT, &ok, FALSE);
1716
1717 if (!ok)
1718 MessageBeep (0);
1719 else {
1720 for (i=0; i<256; i++)
1721 if (SendDlgItemMessage (hwnd, IDC_CCLIST, LB_GETSEL,
1722 i, 0)) {
1723 char str[100];
1724 cfg.wordness[i] = n;
1725 SendDlgItemMessage (hwnd, IDC_CCLIST,
1726 LB_DELETESTRING, i, 0);
1727 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
1728 (i>=0x21 && i != 0x7F) ? i : ' ',
1729 cfg.wordness[i]);
1730 SendDlgItemMessage (hwnd, IDC_CCLIST,
1731 LB_INSERTSTRING, i,
1732 (LPARAM)str);
1733 }
1734 }
1735 }
1736 break;
1737 }
1738 break;
1739 }
1740 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1741 }
1742
1743 static int CALLBACK ColourProc (HWND hwnd, UINT msg,
1744 WPARAM wParam, LPARAM lParam) {
1745 static const char *const colours[] = {
1746 "Default Foreground", "Default Bold Foreground",
1747 "Default Background", "Default Bold Background",
1748 "Cursor Text", "Cursor Colour",
1749 "ANSI Black", "ANSI Black Bold",
1750 "ANSI Red", "ANSI Red Bold",
1751 "ANSI Green", "ANSI Green Bold",
1752 "ANSI Yellow", "ANSI Yellow Bold",
1753 "ANSI Blue", "ANSI Blue Bold",
1754 "ANSI Magenta", "ANSI Magenta Bold",
1755 "ANSI Cyan", "ANSI Cyan Bold",
1756 "ANSI White", "ANSI White Bold"
1757 };
1758 static const int permanent[] = {
1759 TRUE, FALSE, TRUE, FALSE, TRUE, TRUE,
1760 TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE,
1761 TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE
1762 };
1763 struct ctlpos cp;
1764 enum { controlstartvalue = 1000,
1765 IDC_BOLDCOLOUR,
1766 IDC_PALETTE,
1767 IDC_STATIC,
1768 IDC_LIST,
1769 IDC_RSTATIC,
1770 IDC_GSTATIC,
1771 IDC_BSTATIC,
1772 IDC_RVALUE,
1773 IDC_GVALUE,
1774 IDC_BVALUE,
1775 IDC_CHANGE
1776 };
1777
1778 switch (msg) {
1779 case WM_INITDIALOG:
1780 /* Accelerators used: [aco] bmlu */
1781 ctlposinit(&cp, hwnd);
1782 checkbox(&cp, "&Bolded text is a different colour", IDC_BOLDCOLOUR);
1783 checkbox(&cp, "Attempt to use &logical palettes", IDC_PALETTE);
1784 colouredit(&cp, "Select a colo&ur and click to modify it:",
1785 IDC_STATIC, IDC_LIST,
1786 "&Modify...", IDC_CHANGE,
1787 "Red:", IDC_RSTATIC, IDC_RVALUE,
1788 "Green:", IDC_GSTATIC, IDC_GVALUE,
1789 "Blue:", IDC_BSTATIC, IDC_BVALUE, NULL);
1790
1791 CheckDlgButton (hwnd, IDC_BOLDCOLOUR, cfg.bold_colour);
1792 CheckDlgButton (hwnd, IDC_PALETTE, cfg.try_palette);
1793 {
1794 int i;
1795 for (i=0; i<22; i++)
1796 if (cfg.bold_colour || permanent[i])
1797 SendDlgItemMessage (hwnd, IDC_LIST, LB_ADDSTRING, 0,
1798 (LPARAM) colours[i]);
1799 }
1800 SendDlgItemMessage (hwnd, IDC_LIST, LB_SETCURSEL, 0, 0);
1801 SetDlgItemInt (hwnd, IDC_RVALUE, cfg.colours[0][0], FALSE);
1802 SetDlgItemInt (hwnd, IDC_GVALUE, cfg.colours[0][1], FALSE);
1803 SetDlgItemInt (hwnd, IDC_BVALUE, cfg.colours[0][2], FALSE);
1804 break;
1805 case WM_COMMAND:
1806 switch (LOWORD(wParam)) {
1807 case IDC_BOLDCOLOUR:
1808 if (HIWORD(wParam) == BN_CLICKED ||
1809 HIWORD(wParam) == BN_DOUBLECLICKED) {
1810 int n, i;
1811 cfg.bold_colour = IsDlgButtonChecked (hwnd, IDC_BOLDCOLOUR);
1812 n = SendDlgItemMessage (hwnd, IDC_LIST, LB_GETCOUNT, 0, 0);
1813 if (cfg.bold_colour && n!=22) {
1814 for (i=0; i<22; i++)
1815 if (!permanent[i])
1816 SendDlgItemMessage (hwnd, IDC_LIST,
1817 LB_INSERTSTRING, i,
1818 (LPARAM) colours[i]);
1819 } else if (!cfg.bold_colour && n!=12) {
1820 for (i=22; i-- ;)
1821 if (!permanent[i])
1822 SendDlgItemMessage (hwnd, IDC_LIST,
1823 LB_DELETESTRING, i, 0);
1824 }
1825 }
1826 break;
1827 case IDC_PALETTE:
1828 if (HIWORD(wParam) == BN_CLICKED ||
1829 HIWORD(wParam) == BN_DOUBLECLICKED)
1830 cfg.try_palette = IsDlgButtonChecked (hwnd, IDC_PALETTE);
1831 break;
1832 case IDC_LIST:
1833 if (HIWORD(wParam) == LBN_DBLCLK ||
1834 HIWORD(wParam) == LBN_SELCHANGE) {
1835 int i = SendDlgItemMessage (hwnd, IDC_LIST, LB_GETCURSEL,
1836 0, 0);
1837 if (!cfg.bold_colour)
1838 i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
1839 SetDlgItemInt (hwnd, IDC_RVALUE, cfg.colours[i][0], FALSE);
1840 SetDlgItemInt (hwnd, IDC_GVALUE, cfg.colours[i][1], FALSE);
1841 SetDlgItemInt (hwnd, IDC_BVALUE, cfg.colours[i][2], FALSE);
1842 }
1843 break;
1844 case IDC_CHANGE:
1845 if (HIWORD(wParam) == BN_CLICKED ||
1846 HIWORD(wParam) == BN_DOUBLECLICKED) {
1847 static CHOOSECOLOR cc;
1848 static DWORD custom[16] = {0}; /* zero initialisers */
1849 int i = SendDlgItemMessage (hwnd, IDC_LIST, LB_GETCURSEL,
1850 0, 0);
1851 if (!cfg.bold_colour)
1852 i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
1853 cc.lStructSize = sizeof(cc);
1854 cc.hwndOwner = hwnd;
1855 cc.hInstance = (HWND)hinst;
1856 cc.lpCustColors = custom;
1857 cc.rgbResult = RGB (cfg.colours[i][0], cfg.colours[i][1],
1858 cfg.colours[i][2]);
1859 cc.Flags = CC_FULLOPEN | CC_RGBINIT;
1860 if (ChooseColor(&cc)) {
1861 cfg.colours[i][0] =
1862 (unsigned char) (cc.rgbResult & 0xFF);
1863 cfg.colours[i][1] =
1864 (unsigned char) (cc.rgbResult >> 8) & 0xFF;
1865 cfg.colours[i][2] =
1866 (unsigned char) (cc.rgbResult >> 16) & 0xFF;
1867 SetDlgItemInt (hwnd, IDC_RVALUE, cfg.colours[i][0],
1868 FALSE);
1869 SetDlgItemInt (hwnd, IDC_GVALUE, cfg.colours[i][1],
1870 FALSE);
1871 SetDlgItemInt (hwnd, IDC_BVALUE, cfg.colours[i][2],
1872 FALSE);
1873 }
1874 }
1875 break;
1876 }
1877 break;
1878 }
1879 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1880 }
1881
1882 static int CALLBACK TranslationProc (HWND hwnd, UINT msg,
1883 WPARAM wParam, LPARAM lParam) {
1884 struct ctlpos cp;
1885 enum { controlstartvalue = 1000,
1886 IDC_XLATSTATIC,
1887 IDC_NOXLAT,
1888 IDC_KOI8WIN1251,
1889 IDC_88592WIN1250,
1890 IDC_CAPSLOCKCYR,
1891 IDC_VTSTATIC,
1892 IDC_VTXWINDOWS,
1893 IDC_VTOEMANSI,
1894 IDC_VTOEMONLY,
1895 IDC_VTPOORMAN
1896 };
1897
1898 switch (msg) {
1899 case WM_INITDIALOG:
1900 /* Accelerators used: [aco] beiknpsx */
1901 ctlposinit(&cp, hwnd);
1902 radiobig(&cp,
1903 "Handling of VT100 line drawing characters:", IDC_VTSTATIC,
1904 "Font has &XWindows encoding", IDC_VTXWINDOWS,
1905 "Use font in &both ANSI and OEM modes", IDC_VTOEMANSI,
1906 "Use font in O&EM mode only", IDC_VTOEMONLY,
1907 "&Poor man's line drawing (""+"", ""-"" and ""|"")",
1908 IDC_VTPOORMAN, NULL);
1909 radiobig(&cp,
1910 "Character set translation:", IDC_XLATSTATIC,
1911 "&None", IDC_NOXLAT,
1912 "&KOI8 / Win-1251", IDC_KOI8WIN1251,
1913 "&ISO-8859-2 / Win-1250", IDC_88592WIN1250, NULL);
1914 checkbox(&cp, "CAP&S LOCK acts as cyrillic switch", IDC_CAPSLOCKCYR);
1915
1916 CheckRadioButton (hwnd, IDC_NOXLAT, IDC_88592WIN1250,
1917 cfg.xlat_88592w1250 ? IDC_88592WIN1250 :
1918 cfg.xlat_enablekoiwin ? IDC_KOI8WIN1251 :
1919 IDC_NOXLAT);
1920 CheckDlgButton (hwnd, IDC_CAPSLOCKCYR, cfg.xlat_capslockcyr);
1921 CheckRadioButton (hwnd, IDC_VTXWINDOWS, IDC_VTPOORMAN,
1922 cfg.vtmode == VT_XWINDOWS ? IDC_VTXWINDOWS :
1923 cfg.vtmode == VT_OEMANSI ? IDC_VTOEMANSI :
1924 cfg.vtmode == VT_OEMONLY ? IDC_VTOEMONLY :
1925 IDC_VTPOORMAN);
1926 case WM_COMMAND:
1927 switch (LOWORD(wParam)) {
1928 case IDC_NOXLAT:
1929 case IDC_KOI8WIN1251:
1930 case IDC_88592WIN1250:
1931 cfg.xlat_enablekoiwin =
1932 IsDlgButtonChecked (hwnd, IDC_KOI8WIN1251);
1933 cfg.xlat_88592w1250 =
1934 IsDlgButtonChecked (hwnd, IDC_88592WIN1250);
1935 break;
1936 case IDC_CAPSLOCKCYR:
1937 if (HIWORD(wParam) == BN_CLICKED ||
1938 HIWORD(wParam) == BN_DOUBLECLICKED) {
1939 cfg.xlat_capslockcyr =
1940 IsDlgButtonChecked (hwnd, IDC_CAPSLOCKCYR);
1941 }
1942 break;
1943 case IDC_VTXWINDOWS:
1944 case IDC_VTOEMANSI:
1945 case IDC_VTOEMONLY:
1946 case IDC_VTPOORMAN:
1947 cfg.vtmode =
1948 (IsDlgButtonChecked (hwnd, IDC_VTXWINDOWS) ? VT_XWINDOWS :
1949 IsDlgButtonChecked (hwnd, IDC_VTOEMANSI) ? VT_OEMANSI :
1950 IsDlgButtonChecked (hwnd, IDC_VTOEMONLY) ? VT_OEMONLY :
1951 VT_POORMAN);
1952 break;
1953 }
1954 }
1955 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1956 }
1957
1958 static DLGPROC panelproc[NPANELS] = {
1959 ConnectionProc, KeyboardProc, TerminalProc, WindowProc,
1960 TelnetProc, SshProc, SelectionProc, ColourProc, TranslationProc
1961 };
1962
1963 static char *names[NPANELS] = {
1964 "Connection", "Keyboard", "Terminal", "Window", "Telnet",
1965 "SSH", "Selection", "Colours", "Translation"
1966 };
1967
1968 static int mainp[MAIN_NPANELS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8};
1969 static int reconfp[RECONF_NPANELS] = { 0, 1, 2, 3, 6, 7, 8};
1970
1971 static HWND makesubdialog(HWND hwnd, int x, int y, int w, int h,
1972 int n, int dlgtype) {
1973 RECT r;
1974 HWND ret;
1975 WPARAM font;
1976 r.left = x; r.top = y;
1977 r.right = r.left + w; r.bottom = r.top + h;
1978 MapDialogRect(hwnd, &r);
1979 ret = CreateWindowEx(WS_EX_CONTROLPARENT,
1980 WC_DIALOG, "", /* no title */
1981 WS_CHILD | WS_VISIBLE | DS_SETFONT,
1982 r.left, r.top,
1983 r.right-r.left, r.bottom-r.top,
1984 hwnd, (HMENU)IDC_SUBDLG,
1985 hinst, NULL);
1986 SetWindowLong (ret, DWL_DLGPROC, (LONG)panelproc[n]);
1987 font = SendMessage(hwnd, WM_GETFONT, 0, 0);
1988 SendMessage (ret, WM_SETFONT, font, MAKELPARAM(0, 0));
1989 SendMessage (ret, WM_INITDIALOG, dlgtype, 0);
1990 return ret;
1991 }
1992
1993 static int GenericMainDlgProc (HWND hwnd, UINT msg,
1994 WPARAM wParam, LPARAM lParam,
1995 int npanels, int dlgtype,
1996 int *panelnums, HWND *page) {
1997 HWND hw, tabctl;
1998
1999 switch (msg) {
2000 case WM_INITDIALOG:
2001 { /* centre the window */
2002 RECT rs, rd;
2003
2004 hw = GetDesktopWindow();
2005 if (GetWindowRect (hw, &rs) && GetWindowRect (hwnd, &rd))
2006 MoveWindow (hwnd, (rs.right + rs.left + rd.left - rd.right)/2,
2007 (rs.bottom + rs.top + rd.top - rd.bottom)/2,
2008 rd.right-rd.left, rd.bottom-rd.top, TRUE);
2009 }
2010 {
2011 RECT r;
2012 r.left = 3; r.right = r.left + 174;
2013 r.top = 3; r.bottom = r.top + 193;
2014 MapDialogRect(hwnd, &r);
2015 tabctl = CreateWindowEx(0, WC_TABCONTROL, "",
2016 WS_CHILD | WS_VISIBLE |
2017 WS_TABSTOP | TCS_MULTILINE,
2018 r.left, r.top,
2019 r.right-r.left, r.bottom-r.top,
2020 hwnd, (HMENU)IDC_TAB, hinst, NULL);
2021
2022 if (!tabctl) {
2023 struct ctlpos cp;
2024 ctlposinit2(&cp, hwnd);
2025 ersatztab(&cp, "Category:", IDC_TABSTATIC1, IDC_TABLIST,
2026 IDC_TABSTATIC2);
2027 } else {
2028 WPARAM font = SendMessage(hwnd, WM_GETFONT, 0, 0);
2029 SendMessage(tabctl, WM_SETFONT, font, MAKELPARAM(TRUE, 0));
2030 }
2031 }
2032 *page = NULL;
2033 if (tabctl) { /* initialise the tab control */
2034 TC_ITEMHEADER tab;
2035 int i;
2036
2037 for (i=0; i<npanels; i++) {
2038 tab.mask = TCIF_TEXT;
2039 tab.pszText = names[panelnums[i]];
2040 TabCtrl_InsertItem (tabctl, i, &tab);
2041 }
2042 } else {
2043 int i;
2044
2045 for (i=0; i<npanels; i++) {
2046 SendDlgItemMessage(hwnd, IDC_TABLIST, CB_ADDSTRING,
2047 0, (LPARAM)names[panelnums[i]]);
2048 }
2049 SendDlgItemMessage(hwnd, IDC_TABLIST, CB_SETCURSEL, 0, 0);
2050 }
2051 *page = makesubdialog(hwnd, 6, 30, 168, 163, panelnums[0], dlgtype);
2052 SetFocus (*page);
2053 return 0;
2054 case WM_NOTIFY:
2055 if (LOWORD(wParam) == IDC_TAB &&
2056 ((LPNMHDR)lParam)->code == TCN_SELCHANGE) {
2057 int i = TabCtrl_GetCurSel(((LPNMHDR)lParam)->hwndFrom);
2058 if (*page)
2059 DestroyWindow (*page);
2060 *page = makesubdialog(hwnd, 6, 30, 168, 163,
2061 panelnums[i], dlgtype);
2062 SetFocus (((LPNMHDR)lParam)->hwndFrom); /* ensure focus stays */
2063 return 0;
2064 }
2065 break;
2066 case WM_COMMAND:
2067 switch (LOWORD(wParam)) {
2068 case IDC_TABLIST:
2069 if (HIWORD(wParam) == CBN_SELCHANGE) {
2070 HWND tablist = GetDlgItem (hwnd, IDC_TABLIST);
2071 int i = SendMessage (tablist, CB_GETCURSEL, 0, 0);
2072 if (*page)
2073 DestroyWindow (*page);
2074 *page = makesubdialog(hwnd, 6, 30, 168, 163,
2075 panelnums[i], dlgtype);
2076 SetFocus(tablist); /* ensure focus stays */
2077 return 0;
2078 }
2079 break;
2080 case IDOK:
2081 if (*cfg.host)
2082 EndDialog (hwnd, 1);
2083 else
2084 MessageBeep (0);
2085 return 0;
2086 case IDCANCEL:
2087 EndDialog (hwnd, 0);
2088 return 0;
2089 }
2090 return 0;
2091 case WM_CLOSE:
2092 EndDialog (hwnd, 0);
2093 return 0;
2094
2095 /* Grrr Explorer will maximize Dialogs! */
2096 case WM_SIZE:
2097 if (wParam == SIZE_MAXIMIZED)
2098 force_normal(hwnd);
2099 return 0;
2100 }
2101 return 0;
2102 }
2103
2104 static int CALLBACK MainDlgProc (HWND hwnd, UINT msg,
2105 WPARAM wParam, LPARAM lParam) {
2106 static HWND page = NULL;
2107
2108 if (msg == WM_COMMAND && LOWORD(wParam) == IDOK) {
2109 }
2110 if (msg == WM_COMMAND && LOWORD(wParam) == IDC_ABOUT) {
2111 EnableWindow(hwnd, 0);
2112 DialogBox(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
2113 GetParent(hwnd), AboutProc);
2114 EnableWindow(hwnd, 1);
2115 SetActiveWindow(hwnd);
2116 }
2117 return GenericMainDlgProc (hwnd, msg, wParam, lParam,
2118 MAIN_NPANELS, 0, mainp, &page);
2119 }
2120
2121 static int CALLBACK ReconfDlgProc (HWND hwnd, UINT msg,
2122 WPARAM wParam, LPARAM lParam) {
2123 static HWND page;
2124 return GenericMainDlgProc (hwnd, msg, wParam, lParam,
2125 RECONF_NPANELS, 1, reconfp, &page);
2126 }
2127
2128 int do_config (void) {
2129 int ret;
2130
2131 get_sesslist(TRUE);
2132 savedsession[0] = '\0';
2133 ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_MAINBOX), NULL, MainDlgProc);
2134 get_sesslist(FALSE);
2135
2136 return ret;
2137 }
2138
2139 int do_reconfig (HWND hwnd) {
2140 Config backup_cfg;
2141 int ret;
2142
2143 backup_cfg = cfg; /* structure copy */
2144 ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_RECONF), hwnd, ReconfDlgProc);
2145 if (!ret)
2146 cfg = backup_cfg; /* structure copy */
2147 else
2148 force_normal(hwnd);
2149
2150 return ret;
2151 }
2152
2153 void logevent (char *string) {
2154 if (nevents >= negsize) {
2155 negsize += 64;
2156 events = srealloc (events, negsize * sizeof(*events));
2157 }
2158 events[nevents] = smalloc(1+strlen(string));
2159 strcpy (events[nevents], string);
2160 nevents++;
2161 if (logbox) {
2162 int count;
2163 SendDlgItemMessage (logbox, IDN_LIST, LB_ADDSTRING,
2164 0, (LPARAM)string);
2165 count = SendDlgItemMessage (logbox, IDN_LIST, LB_GETCOUNT, 0, 0);
2166 SendDlgItemMessage (logbox, IDN_LIST, LB_SETTOPINDEX, count-1, 0);
2167 }
2168 }
2169
2170 void showeventlog (HWND hwnd) {
2171 if (!logbox) {
2172 logbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_LOGBOX),
2173 hwnd, LogProc);
2174 ShowWindow (logbox, SW_SHOWNORMAL);
2175 }
2176 }
2177
2178 void showabout (HWND hwnd) {
2179 if (!abtbox) {
2180 abtbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
2181 hwnd, AboutProc);
2182 ShowWindow (abtbox, SW_SHOWNORMAL);
2183 }
2184 }
2185
2186 void verify_ssh_host_key(char *host, int port, char *keytype,
2187 char *keystr, char *fingerprint) {
2188 int ret;
2189
2190 static const char absentmsg[] =
2191 "The server's host key is not cached in the registry. You\n"
2192 "have no guarantee that the server is the computer you\n"
2193 "think it is.\n"
2194 "The server's key fingerprint is:\n"
2195 "%s\n"
2196 "If you trust this host, hit Yes to add the key to\n"
2197 "PuTTY's cache and carry on connecting.\n"
2198 "If you do not trust this host, hit No to abandon the\n"
2199 "connection.\n";
2200
2201 static const char wrongmsg[] =
2202 "WARNING - POTENTIAL SECURITY BREACH!\n"
2203 "\n"
2204 "The server's host key does not match the one PuTTY has\n"
2205 "cached in the registry. This means that either the\n"
2206 "server administrator has changed the host key, or you\n"
2207 "have actually connected to another computer pretending\n"
2208 "to be the server.\n"
2209 "The new key fingerprint is:\n"
2210 "%s\n"
2211 "If you were expecting this change and trust the new key,\n"
2212 "hit Yes to update PuTTY's cache and continue connecting.\n"
2213 "If you want to carry on connecting but without updating\n"
2214 "the cache, hit No.\n"
2215 "If you want to abandon the connection completely, hit\n"
2216 "Cancel. Hitting Cancel is the ONLY guaranteed safe\n"
2217 "choice.\n";
2218
2219 static const char mbtitle[] = "PuTTY Security Alert";
2220
2221
2222 char message[160+ /* sensible fingerprint max size */
2223 (sizeof(absentmsg) > sizeof(wrongmsg) ?
2224 sizeof(absentmsg) : sizeof(wrongmsg))];
2225
2226 /*
2227 * Verify the key against the registry.
2228 */
2229 ret = verify_host_key(host, port, keytype, keystr);
2230
2231 if (ret == 0) /* success - key matched OK */
2232 return;
2233 if (ret == 2) { /* key was different */
2234 int mbret;
2235 sprintf(message, wrongmsg, fingerprint);
2236 mbret = MessageBox(NULL, message, mbtitle,
2237 MB_ICONWARNING | MB_YESNOCANCEL);
2238 if (mbret == IDYES)
2239 store_host_key(host, port, keytype, keystr);
2240 if (mbret == IDCANCEL)
2241 exit(0);
2242 }
2243 if (ret == 1) { /* key was absent */
2244 int mbret;
2245 sprintf(message, absentmsg, fingerprint);
2246 mbret = MessageBox(NULL, message, mbtitle,
2247 MB_ICONWARNING | MB_YESNO);
2248 if (mbret == IDNO)
2249 exit(0);
2250 store_host_key(host, port, keytype, keystr);
2251 }
2252 }