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