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