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