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