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