20 #define MAIN_NPANELS 9
21 #define RECONF_NPANELS 6
23 static char **events = NULL;
24 static int nevents = 0, negsize = 0;
26 static HWND logbox = NULL, abtbox = NULL;
28 static void gpps(void *handle, char *name, char *def, char *val, int len) {
29 if (!read_setting_s(handle, name, val, len)) {
30 strncpy(val, def, len);
35 static void gppi(void *handle, char *name, int def, int *i) {
36 *i = read_setting_i(handle, name, def);
39 static HINSTANCE hinst;
43 static void save_settings (char *section, int do_host) {
48 sesskey = open_settings_w(section);
52 write_setting_i (sesskey, "Present", 1);
54 write_setting_s (sesskey, "HostName", cfg.host);
55 write_setting_i (sesskey, "PortNumber", cfg.port);
57 for (i = 0; backends[i].name != NULL; i++)
58 if (backends[i].protocol == cfg.protocol) {
62 write_setting_s (sesskey, "Protocol", p);
64 write_setting_i (sesskey, "CloseOnExit", !!cfg.close_on_exit);
65 write_setting_i (sesskey, "WarnOnClose", !!cfg.warn_on_close);
66 write_setting_s (sesskey, "TerminalType", cfg.termtype);
67 write_setting_s (sesskey, "TerminalSpeed", cfg.termspeed);
69 char buf[2*sizeof(cfg.environmt)], *p, *q;
75 if (c == '=' || c == ',' || c == '\\')
85 write_setting_s (sesskey, "Environment", buf);
87 write_setting_s (sesskey, "UserName", cfg.username);
88 write_setting_i (sesskey, "NoPTY", cfg.nopty);
89 write_setting_i (sesskey, "AgentFwd", cfg.agentfwd);
90 write_setting_s (sesskey, "RemoteCmd", cfg.remote_cmd);
91 write_setting_s (sesskey, "Cipher", cfg.cipher == CIPHER_BLOWFISH ? "blowfish" :
92 cfg.cipher == CIPHER_DES ? "des" : "3des");
93 write_setting_i (sesskey, "AuthTIS", cfg.try_tis_auth);
94 write_setting_i (sesskey, "SshProt", cfg.sshprot);
95 write_setting_s (sesskey, "PublicKeyFile", cfg.keyfile);
96 write_setting_s (sesskey, "RemoteCommand", cfg.remote_cmd);
97 write_setting_i (sesskey, "RFCEnviron", cfg.rfc_environ);
98 write_setting_i (sesskey, "BackspaceIsDelete", cfg.bksp_is_delete);
99 write_setting_i (sesskey, "RXVTHomeEnd", cfg.rxvt_homeend);
100 write_setting_i (sesskey, "LinuxFunctionKeys", cfg.funky_type);
101 write_setting_i (sesskey, "ApplicationCursorKeys", cfg.app_cursor);
102 write_setting_i (sesskey, "ApplicationKeypad", cfg.app_keypad);
103 write_setting_i (sesskey, "NetHackKeypad", cfg.nethack_keypad);
104 write_setting_i (sesskey, "AltF4", cfg.alt_f4);
105 write_setting_i (sesskey, "AltSpace", cfg.alt_space);
106 write_setting_i (sesskey, "LdiscTerm", cfg.ldisc_term);
107 write_setting_i (sesskey, "BlinkCur", cfg.blink_cur);
108 write_setting_i (sesskey, "Beep", cfg.beep);
109 write_setting_i (sesskey, "ScrollbackLines", cfg.savelines);
110 write_setting_i (sesskey, "DECOriginMode", cfg.dec_om);
111 write_setting_i (sesskey, "AutoWrapMode", cfg.wrap_mode);
112 write_setting_i (sesskey, "LFImpliesCR", cfg.lfhascr);
113 write_setting_i (sesskey, "WinNameAlways", cfg.win_name_always);
114 write_setting_s (sesskey, "WinTitle", cfg.wintitle);
115 write_setting_i (sesskey, "TermWidth", cfg.width);
116 write_setting_i (sesskey, "TermHeight", cfg.height);
117 write_setting_s (sesskey, "Font", cfg.font);
118 write_setting_i (sesskey, "FontIsBold", cfg.fontisbold);
119 write_setting_i (sesskey, "FontCharSet", cfg.fontcharset);
120 write_setting_i (sesskey, "FontHeight", cfg.fontheight);
121 write_setting_i (sesskey, "FontVTMode", cfg.vtmode);
122 write_setting_i (sesskey, "TryPalette", cfg.try_palette);
123 write_setting_i (sesskey, "BoldAsColour", cfg.bold_colour);
124 for (i=0; i<22; i++) {
125 char buf[20], buf2[30];
126 sprintf(buf, "Colour%d", i);
127 sprintf(buf2, "%d,%d,%d", cfg.colours[i][0],
128 cfg.colours[i][1], cfg.colours[i][2]);
129 write_setting_s (sesskey, buf, buf2);
131 write_setting_i (sesskey, "MouseIsXterm", cfg.mouse_is_xterm);
132 for (i=0; i<256; i+=32) {
133 char buf[20], buf2[256];
135 sprintf(buf, "Wordness%d", i);
137 for (j=i; j<i+32; j++) {
138 sprintf(buf2+strlen(buf2), "%s%d",
139 (*buf2 ? "," : ""), cfg.wordness[j]);
141 write_setting_s (sesskey, buf, buf2);
143 write_setting_i (sesskey, "KoiWinXlat", cfg.xlat_enablekoiwin);
144 write_setting_i (sesskey, "88592Xlat", cfg.xlat_88592w1250);
145 write_setting_i (sesskey, "CapsLockCyr", cfg.xlat_capslockcyr);
146 write_setting_i (sesskey, "ScrollBar", cfg.scrollbar);
147 write_setting_i (sesskey, "ScrollOnKey", cfg.scroll_on_key);
148 write_setting_i (sesskey, "LockSize", cfg.locksize);
149 write_setting_i (sesskey, "BCE", cfg.bce);
150 write_setting_i (sesskey, "BlinkText", cfg.blinktext);
152 close_settings_w(sesskey);
155 static void load_settings (char *section, int do_host) {
160 sesskey = open_settings_r(section);
162 gpps (sesskey, "HostName", "", cfg.host, sizeof(cfg.host));
163 gppi (sesskey, "PortNumber", default_port, &cfg.port);
165 gpps (sesskey, "Protocol", "default", prot, 10);
166 cfg.protocol = default_protocol;
167 for (i = 0; backends[i].name != NULL; i++)
168 if (!strcmp(prot, backends[i].name)) {
169 cfg.protocol = backends[i].protocol;
173 gppi (sesskey, "CloseOnExit", 1, &cfg.close_on_exit);
174 gppi (sesskey, "WarnOnClose", 1, &cfg.warn_on_close);
175 gpps (sesskey, "TerminalType", "xterm", cfg.termtype,
176 sizeof(cfg.termtype));
177 gpps (sesskey, "TerminalSpeed", "38400,38400", cfg.termspeed,
178 sizeof(cfg.termspeed));
180 char buf[2*sizeof(cfg.environmt)], *p, *q;
181 gpps (sesskey, "Environment", "", buf, sizeof(buf));
185 while (*p && *p != ',') {
198 gpps (sesskey, "UserName", "", cfg.username, sizeof(cfg.username));
199 gppi (sesskey, "NoPTY", 0, &cfg.nopty);
200 gppi (sesskey, "AgentFwd", 0, &cfg.agentfwd);
201 gpps (sesskey, "RemoteCmd", "", cfg.remote_cmd, sizeof(cfg.remote_cmd));
204 gpps (sesskey, "Cipher", "3des", cipher, 10);
205 if (!strcmp(cipher, "blowfish"))
206 cfg.cipher = CIPHER_BLOWFISH;
207 else if (!strcmp(cipher, "des"))
208 cfg.cipher = CIPHER_DES;
210 cfg.cipher = CIPHER_3DES;
212 gppi (sesskey, "SshProt", 1, &cfg.sshprot);
213 gppi (sesskey, "AuthTIS", 0, &cfg.try_tis_auth);
214 gpps (sesskey, "PublicKeyFile", "", cfg.keyfile, sizeof(cfg.keyfile));
215 gpps (sesskey, "RemoteCommand", "", cfg.remote_cmd,
216 sizeof(cfg.remote_cmd));
217 gppi (sesskey, "RFCEnviron", 0, &cfg.rfc_environ);
218 gppi (sesskey, "BackspaceIsDelete", 1, &cfg.bksp_is_delete);
219 gppi (sesskey, "RXVTHomeEnd", 0, &cfg.rxvt_homeend);
220 gppi (sesskey, "LinuxFunctionKeys", 0, &cfg.funky_type);
221 gppi (sesskey, "ApplicationCursorKeys", 0, &cfg.app_cursor);
222 gppi (sesskey, "ApplicationKeypad", 0, &cfg.app_keypad);
223 gppi (sesskey, "NetHackKeypad", 0, &cfg.nethack_keypad);
224 gppi (sesskey, "AltF4", 1, &cfg.alt_f4);
225 gppi (sesskey, "AltSpace", 0, &cfg.alt_space);
226 gppi (sesskey, "LdiscTerm", 0, &cfg.ldisc_term);
227 gppi (sesskey, "BlinkCur", 0, &cfg.blink_cur);
228 gppi (sesskey, "Beep", 1, &cfg.beep);
229 gppi (sesskey, "ScrollbackLines", 200, &cfg.savelines);
230 gppi (sesskey, "DECOriginMode", 0, &cfg.dec_om);
231 gppi (sesskey, "AutoWrapMode", 1, &cfg.wrap_mode);
232 gppi (sesskey, "LFImpliesCR", 0, &cfg.lfhascr);
233 gppi (sesskey, "WinNameAlways", 0, &cfg.win_name_always);
234 gpps (sesskey, "WinTitle", "", cfg.wintitle, sizeof(cfg.wintitle));
235 gppi (sesskey, "TermWidth", 80, &cfg.width);
236 gppi (sesskey, "TermHeight", 24, &cfg.height);
237 gpps (sesskey, "Font", "Courier", cfg.font, sizeof(cfg.font));
238 gppi (sesskey, "FontIsBold", 0, &cfg.fontisbold);
239 gppi (sesskey, "FontCharSet", ANSI_CHARSET, &cfg.fontcharset);
240 gppi (sesskey, "FontHeight", 10, &cfg.fontheight);
241 gppi (sesskey, "FontVTMode", VT_OEMANSI, (int *)&cfg.vtmode);
242 gppi (sesskey, "TryPalette", 0, &cfg.try_palette);
243 gppi (sesskey, "BoldAsColour", 1, &cfg.bold_colour);
244 for (i=0; i<22; i++) {
245 static char *defaults[] = {
246 "187,187,187", "255,255,255", "0,0,0", "85,85,85", "0,0,0",
247 "0,255,0", "0,0,0", "85,85,85", "187,0,0", "255,85,85",
248 "0,187,0", "85,255,85", "187,187,0", "255,255,85", "0,0,187",
249 "85,85,255", "187,0,187", "255,85,255", "0,187,187",
250 "85,255,255", "187,187,187", "255,255,255"
252 char buf[20], buf2[30];
254 sprintf(buf, "Colour%d", i);
255 gpps (sesskey, buf, defaults[i], buf2, sizeof(buf2));
256 if(sscanf(buf2, "%d,%d,%d", &c0, &c1, &c2) == 3) {
257 cfg.colours[i][0] = c0;
258 cfg.colours[i][1] = c1;
259 cfg.colours[i][2] = c2;
262 gppi (sesskey, "MouseIsXterm", 0, &cfg.mouse_is_xterm);
263 for (i=0; i<256; i+=32) {
264 static char *defaults[] = {
265 "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0",
266 "0,1,2,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1",
267 "1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,2",
268 "1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1",
269 "1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1",
270 "1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1",
271 "2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2",
272 "2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2"
274 char buf[20], buf2[256], *p;
276 sprintf(buf, "Wordness%d", i);
277 gpps (sesskey, buf, defaults[i/32], buf2, sizeof(buf2));
279 for (j=i; j<i+32; j++) {
281 while (*p && *p != ',') p++;
282 if (*p == ',') *p++ = '\0';
283 cfg.wordness[j] = atoi(q);
286 gppi (sesskey, "KoiWinXlat", 0, &cfg.xlat_enablekoiwin);
287 gppi (sesskey, "88592Xlat", 0, &cfg.xlat_88592w1250);
288 gppi (sesskey, "CapsLockCyr", 0, &cfg.xlat_capslockcyr);
289 gppi (sesskey, "ScrollBar", 1, &cfg.scrollbar);
290 gppi (sesskey, "ScrollOnKey", 0, &cfg.scroll_on_key);
291 gppi (sesskey, "LockSize", 0, &cfg.locksize);
292 gppi (sesskey, "BCE", 0, &cfg.bce);
293 gppi (sesskey, "BlinkText", 0, &cfg.blinktext);
295 close_settings_r(sesskey);
298 static void force_normal(HWND hwnd)
300 static int recurse = 0;
307 wp.length = sizeof(wp);
308 if (GetWindowPlacement(hwnd, &wp))
310 wp.showCmd = SW_SHOWNORMAL;
311 SetWindowPlacement(hwnd, &wp);
316 static void MyGetDlgItemInt (HWND hwnd, int id, int *result) {
319 n = GetDlgItemInt (hwnd, id, &ok, FALSE);
324 static int CALLBACK LogProc (HWND hwnd, UINT msg,
325 WPARAM wParam, LPARAM lParam) {
330 for (i=0; i<nevents; i++)
331 SendDlgItemMessage (hwnd, IDN_LIST, LB_ADDSTRING,
332 0, (LPARAM)events[i]);
335 switch (LOWORD(wParam)) {
338 DestroyWindow (hwnd);
341 if (HIWORD(wParam) == BN_CLICKED ||
342 HIWORD(wParam) == BN_DOUBLECLICKED) {
345 selcount = SendDlgItemMessage(hwnd, IDN_LIST,
346 LB_GETSELCOUNT, 0, 0);
347 selitems = malloc(selcount * sizeof(int));
349 int count = SendDlgItemMessage(hwnd, IDN_LIST,
351 selcount, (LPARAM)selitems);
355 static unsigned char sel_nl[] = SEL_NL;
358 for (i = 0; i < count; i++)
359 size += strlen(events[selitems[i]]) + sizeof(sel_nl);
361 clipdata = malloc(size);
364 for (i = 0; i < count; i++) {
365 char *q = events[selitems[i]];
366 int qlen = strlen(q);
369 memcpy(p, sel_nl, sizeof(sel_nl));
372 write_clip(clipdata, size);
384 DestroyWindow (hwnd);
390 static int CALLBACK LicenceProc (HWND hwnd, UINT msg,
391 WPARAM wParam, LPARAM lParam) {
396 switch (LOWORD(wParam)) {
409 static int CALLBACK AboutProc (HWND hwnd, UINT msg,
410 WPARAM wParam, LPARAM lParam) {
413 SetDlgItemText (hwnd, IDA_VERSION, ver);
416 switch (LOWORD(wParam)) {
419 DestroyWindow (hwnd);
422 EnableWindow(hwnd, 0);
423 DialogBox (hinst, MAKEINTRESOURCE(IDD_LICENCEBOX),
425 EnableWindow(hwnd, 1);
426 SetActiveWindow(hwnd);
432 DestroyWindow (hwnd);
438 /* ----------------------------------------------------------------------
439 * Routines to self-manage the controls in a dialog box.
445 #define STATICHEIGHT 8
446 #define CHECKBOXHEIGHT 8
447 #define RADIOHEIGHT 8
448 #define EDITHEIGHT 12
449 #define COMBOHEIGHT 12
450 #define PUSHBTNHEIGHT 14
459 /* Used on self-constructed dialogs. */
460 static void ctlposinit(struct ctlpos *cp, HWND hwnd) {
463 cp->units = GetWindowLong(hwnd, GWL_USERDATA);
464 cp->font = GetWindowLong(hwnd, DWL_USER);
465 cp->ypos = GAPBETWEEN;
466 GetClientRect(hwnd, &r);
467 cp->width = (r.right * 4) / (cp->units & 0xFFFF) - 2*GAPBETWEEN;
470 /* Used on kosher dialogs. */
471 static void ctlposinit2(struct ctlpos *cp, HWND hwnd) {
477 MapDialogRect(hwnd, &r);
478 cp->units = (r.bottom << 16) | r.right;
479 cp->font = SendMessage(hwnd, WM_GETFONT, 0, 0);
480 cp->ypos = GAPBETWEEN;
481 GetClientRect(hwnd, &r);
482 cp->width = (r.right * 4) / (cp->units & 0xFFFF) - 2*GAPBETWEEN;
485 static void doctl(struct ctlpos *cp, RECT r,
486 char *wclass, int wstyle, int exstyle,
487 char *wtext, int wid) {
490 * Note nonstandard use of RECT. This is deliberate: by
491 * transforming the width and height directly we arrange to
492 * have all supposedly same-sized controls really same-sized.
495 /* MapDialogRect, or its near equivalent. */
496 r.left = (r.left * (cp->units & 0xFFFF)) / 4;
497 r.right = (r.right * (cp->units & 0xFFFF)) / 4;
498 r.top = (r.top * ((cp->units>>16) & 0xFFFF)) / 8;
499 r.bottom = (r.bottom * ((cp->units>>16) & 0xFFFF)) / 8;
501 ctl = CreateWindowEx(exstyle, wclass, wtext, wstyle,
502 r.left, r.top, r.right, r.bottom,
503 cp->hwnd, (HMENU)wid, hinst, NULL);
504 SendMessage(ctl, WM_SETFONT, cp->font, MAKELPARAM(TRUE, 0));
508 * Some edit boxes. Each one has a static above it. The percentages
509 * of the horizontal space are provided.
511 static void multiedit(struct ctlpos *cp, ...) {
520 int staticid, editid, pcwidth;
521 text = va_arg(ap, char *);
524 staticid = va_arg(ap, int);
525 editid = va_arg(ap, int);
526 pcwidth = va_arg(ap, int);
528 r.left = xpos + GAPBETWEEN;
530 xpos = (cp->width + GAPBETWEEN) * percent / 100;
531 r.right = xpos - r.left;
533 r.top = cp->ypos; r.bottom = STATICHEIGHT;
534 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0,
536 r.top = cp->ypos + 8 + GAPWITHIN; r.bottom = EDITHEIGHT;
538 WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
543 cp->ypos += 8+GAPWITHIN+12+GAPBETWEEN;
547 * A set of radio buttons on the same line, with a static above
548 * them. `nacross' dictates how many parts the line is divided into
549 * (you might want this not to equal the number of buttons if you
550 * needed to line up some 2s and some 3s to look good in the same
553 static void radioline(struct ctlpos *cp,
554 char *text, int id, int nacross, ...) {
560 r.left = GAPBETWEEN; r.top = cp->ypos;
561 r.right = cp->width; r.bottom = STATICHEIGHT;
562 cp->ypos += r.bottom + GAPWITHIN;
563 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, text, id);
564 va_start(ap, nacross);
570 btext = va_arg(ap, char *);
573 bid = va_arg(ap, int);
574 r.left = GAPBETWEEN + i * (cp->width+GAPBETWEEN)/nacross;
575 r.right = (i+1) * (cp->width+GAPBETWEEN)/nacross - r.left;
576 r.top = cp->ypos; r.bottom = RADIOHEIGHT;
577 doctl(cp, r, "BUTTON",
578 BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP | group,
585 cp->ypos += r.bottom + GAPBETWEEN;
589 * A set of radio buttons on multiple lines, with a static above
592 static void radiobig(struct ctlpos *cp, char *text, int id, ...) {
597 r.left = GAPBETWEEN; r.top = cp->ypos;
598 r.right = cp->width; r.bottom = STATICHEIGHT;
599 cp->ypos += r.bottom + GAPWITHIN;
600 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, text, id);
606 btext = va_arg(ap, char *);
609 bid = va_arg(ap, int);
610 r.left = GAPBETWEEN; r.top = cp->ypos;
611 r.right = cp->width; r.bottom = STATICHEIGHT;
612 cp->ypos += r.bottom + GAPWITHIN;
613 doctl(cp, r, "BUTTON",
614 BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP | group,
620 cp->ypos += GAPBETWEEN - GAPWITHIN;
624 * A single standalone checkbox.
626 static void checkbox(struct ctlpos *cp, char *text, int id) {
629 r.left = GAPBETWEEN; r.top = cp->ypos;
630 r.right = cp->width; r.bottom = CHECKBOXHEIGHT;
631 cp->ypos += r.bottom + GAPBETWEEN;
632 doctl(cp, r, "BUTTON",
633 BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0,
638 * A button on the right hand side, with a static to its left.
640 static void staticbtn(struct ctlpos *cp, char *stext, int sid,
641 char *btext, int bid) {
642 const int height = (PUSHBTNHEIGHT > STATICHEIGHT ?
643 PUSHBTNHEIGHT : STATICHEIGHT);
645 int lwid, rwid, rpos;
647 rpos = GAPBETWEEN + 3 * (cp->width + GAPBETWEEN) / 4;
648 lwid = rpos - 2*GAPBETWEEN;
649 rwid = cp->width + GAPBETWEEN - rpos;
651 r.left = GAPBETWEEN; r.top = cp->ypos + (height-STATICHEIGHT)/2;
652 r.right = lwid; r.bottom = STATICHEIGHT;
653 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
655 r.left = rpos; r.top = cp->ypos + (height-PUSHBTNHEIGHT)/2;
656 r.right = rwid; r.bottom = PUSHBTNHEIGHT;
657 doctl(cp, r, "BUTTON",
658 WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
662 cp->ypos += height + GAPBETWEEN;
666 * An edit control on the right hand side, with a static to its left.
668 static void staticedit(struct ctlpos *cp, char *stext, int sid, int eid) {
669 const int height = (EDITHEIGHT > STATICHEIGHT ?
670 EDITHEIGHT : STATICHEIGHT);
672 int lwid, rwid, rpos;
674 rpos = GAPBETWEEN + (cp->width + GAPBETWEEN) / 2;
675 lwid = rpos - 2*GAPBETWEEN;
676 rwid = cp->width + GAPBETWEEN - rpos;
678 r.left = GAPBETWEEN; r.top = cp->ypos + (height-STATICHEIGHT)/2;
679 r.right = lwid; r.bottom = STATICHEIGHT;
680 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
682 r.left = rpos; r.top = cp->ypos + (height-EDITHEIGHT)/2;
683 r.right = rwid; r.bottom = EDITHEIGHT;
685 WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
689 cp->ypos += height + GAPBETWEEN;
693 * A tab-control substitute when a real tab control is unavailable.
695 static void ersatztab(struct ctlpos *cp, char *stext, int sid,
697 const int height = (COMBOHEIGHT > STATICHEIGHT ?
698 COMBOHEIGHT : STATICHEIGHT);
700 int bigwid, lwid, rwid, rpos;
701 static const int BIGGAP = 15;
702 static const int MEDGAP = 3;
704 bigwid = cp->width + 2*GAPBETWEEN - 2*BIGGAP;
706 rpos = BIGGAP + (bigwid + BIGGAP) / 2;
707 lwid = rpos - 2*BIGGAP;
708 rwid = bigwid + BIGGAP - rpos;
710 r.left = BIGGAP; r.top = cp->ypos + (height-STATICHEIGHT)/2;
711 r.right = lwid; r.bottom = STATICHEIGHT;
712 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
714 r.left = rpos; r.top = cp->ypos + (height-COMBOHEIGHT)/2;
715 r.right = rwid; r.bottom = COMBOHEIGHT*10;
716 doctl(cp, r, "COMBOBOX",
717 WS_CHILD | WS_VISIBLE | WS_TABSTOP |
718 CBS_DROPDOWNLIST | CBS_HASSTRINGS,
722 cp->ypos += height + MEDGAP + GAPBETWEEN;
724 r.left = GAPBETWEEN; r.top = cp->ypos;
725 r.right = cp->width; r.bottom = 2;
726 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE | SS_ETCHEDHORZ,
731 * A static line, followed by an edit control on the left hand side
732 * and a button on the right.
734 static void editbutton(struct ctlpos *cp, char *stext, int sid,
735 int eid, char *btext, int bid) {
736 const int height = (EDITHEIGHT > PUSHBTNHEIGHT ?
737 EDITHEIGHT : PUSHBTNHEIGHT);
739 int lwid, rwid, rpos;
741 r.left = GAPBETWEEN; r.top = cp->ypos;
742 r.right = cp->width; r.bottom = STATICHEIGHT;
743 cp->ypos += r.bottom + GAPWITHIN;
744 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
746 rpos = GAPBETWEEN + 3 * (cp->width + GAPBETWEEN) / 4;
747 lwid = rpos - 2*GAPBETWEEN;
748 rwid = cp->width + GAPBETWEEN - rpos;
750 r.left = GAPBETWEEN; r.top = cp->ypos + (height-EDITHEIGHT)/2;
751 r.right = lwid; r.bottom = EDITHEIGHT;
753 WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
757 r.left = rpos; r.top = cp->ypos + (height-PUSHBTNHEIGHT)/2;
758 r.right = rwid; r.bottom = PUSHBTNHEIGHT;
759 doctl(cp, r, "BUTTON",
760 WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
764 cp->ypos += height + GAPBETWEEN;
768 * Special control which was hard to describe generically: the
769 * session-saver assembly. A static; below that an edit box; below
770 * that a list box. To the right of the list box, a column of
773 static void sesssaver(struct ctlpos *cp, char *text,
774 int staticid, int editid, int listid, ...) {
777 int lwid, rwid, rpos;
779 const int LISTDEFHEIGHT = 66;
781 rpos = GAPBETWEEN + 3 * (cp->width + GAPBETWEEN) / 4;
782 lwid = rpos - 2*GAPBETWEEN;
783 rwid = cp->width + GAPBETWEEN - rpos;
785 /* The static control. */
786 r.left = GAPBETWEEN; r.top = cp->ypos;
787 r.right = lwid; r.bottom = STATICHEIGHT;
788 cp->ypos += r.bottom + GAPWITHIN;
789 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, text, staticid);
791 /* The edit control. */
792 r.left = GAPBETWEEN; r.top = cp->ypos;
793 r.right = lwid; r.bottom = EDITHEIGHT;
794 cp->ypos += r.bottom + GAPWITHIN;
796 WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
801 * The buttons (we should hold off on the list box until we
802 * know how big the buttons are).
804 va_start(ap, listid);
807 char *btext = va_arg(ap, char *);
810 bid = va_arg(ap, int);
811 r.left = rpos; r.top = y;
812 r.right = rwid; r.bottom = PUSHBTNHEIGHT;
813 y += r.bottom + GAPWITHIN;
814 doctl(cp, r, "BUTTON",
815 WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
820 /* Compute list box height. LISTDEFHEIGHT, or height of buttons. */
823 if (y < LISTDEFHEIGHT) y = LISTDEFHEIGHT;
824 r.left = GAPBETWEEN; r.top = cp->ypos;
825 r.right = lwid; r.bottom = y;
826 cp->ypos += y + GAPBETWEEN;
827 doctl(cp, r, "LISTBOX",
828 WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL |
829 LBS_STANDARD | LBS_HASSTRINGS,
835 * Another special control: the environment-variable setter. A
836 * static line first; then a pair of edit boxes with associated
837 * statics, and two buttons; then a list box.
839 static void envsetter(struct ctlpos *cp, char *stext, int sid,
840 char *e1stext, int e1sid, int e1id,
841 char *e2stext, int e2sid, int e2id,
843 char *b1text, int b1id, char *b2text, int b2id) {
845 const int height = (STATICHEIGHT > EDITHEIGHT && STATICHEIGHT > PUSHBTNHEIGHT ?
847 EDITHEIGHT > PUSHBTNHEIGHT ?
848 EDITHEIGHT : PUSHBTNHEIGHT);
849 const static int percents[] = { 20, 35, 10, 25 };
850 int i, j, xpos, percent;
851 const int LISTHEIGHT = 42;
853 /* The static control. */
854 r.left = GAPBETWEEN; r.top = cp->ypos;
855 r.right = cp->width; r.bottom = STATICHEIGHT;
856 cp->ypos += r.bottom + GAPWITHIN;
857 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
859 /* The statics+edits+buttons. */
860 for (j = 0; j < 2; j++) {
862 for (i = 0; i < 4; i++) {
863 xpos = (cp->width + GAPBETWEEN) * percent / 100;
864 r.left = xpos + GAPBETWEEN;
865 percent += percents[i];
866 xpos = (cp->width + GAPBETWEEN) * percent / 100;
867 r.right = xpos - r.left;
869 r.bottom = (i==0 ? STATICHEIGHT :
872 r.top += (height-r.bottom)/2;
874 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0,
875 j==0 ? e1stext : e2stext, j==0 ? e1sid : e2sid);
878 WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
880 "", j==0 ? e1id : e2id);
882 doctl(cp, r, "BUTTON",
883 WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
885 j==0 ? b1text : b2text, j==0 ? b1id : b2id);
888 cp->ypos += height + GAPWITHIN;
892 r.left = GAPBETWEEN; r.top = cp->ypos;
893 r.right = cp->width; r.bottom = LISTHEIGHT;
894 cp->ypos += r.bottom + GAPBETWEEN;
895 doctl(cp, r, "LISTBOX",
896 WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL | LBS_HASSTRINGS |
903 * Yet another special control: the character-class setter. A
904 * static, then a list, then a line containing a
905 * button-and-static-and-edit.
907 static void charclass(struct ctlpos *cp, char *stext, int sid, int listid,
908 char *btext, int bid, int eid, char *s2text, int s2id) {
910 const int height = (STATICHEIGHT > EDITHEIGHT && STATICHEIGHT > PUSHBTNHEIGHT ?
912 EDITHEIGHT > PUSHBTNHEIGHT ?
913 EDITHEIGHT : PUSHBTNHEIGHT);
914 const static int percents[] = { 30, 40, 30 };
915 int i, xpos, percent;
916 const int LISTHEIGHT = 66;
918 /* The static control. */
919 r.left = GAPBETWEEN; r.top = cp->ypos;
920 r.right = cp->width; r.bottom = STATICHEIGHT;
921 cp->ypos += r.bottom + GAPWITHIN;
922 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
925 r.left = GAPBETWEEN; r.top = cp->ypos;
926 r.right = cp->width; r.bottom = LISTHEIGHT;
927 cp->ypos += r.bottom + GAPWITHIN;
928 doctl(cp, r, "LISTBOX",
929 WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL | LBS_HASSTRINGS |
934 /* The button+static+edit. */
936 for (i = 0; i < 3; i++) {
937 r.left = xpos + GAPBETWEEN;
938 percent += percents[i];
939 xpos = (cp->width + GAPBETWEEN) * percent / 100;
940 r.right = xpos - r.left;
942 r.bottom = (i==0 ? PUSHBTNHEIGHT :
943 i==1 ? STATICHEIGHT :
945 r.top += (height-r.bottom)/2;
947 doctl(cp, r, "BUTTON",
948 WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
951 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE | SS_CENTER,
955 WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
956 WS_EX_CLIENTEDGE, "", eid);
959 cp->ypos += height + GAPBETWEEN;
963 * A special control (horrors!). The colour editor. A static line;
964 * then on the left, a list box, and on the right, a sequence of
965 * two-part statics followed by a button.
967 static void colouredit(struct ctlpos *cp, char *stext, int sid, int listid,
968 char *btext, int bid, ...) {
972 int lwid, rwid, rpos;
973 const int LISTHEIGHT = 66;
975 /* The static control. */
976 r.left = GAPBETWEEN; r.top = cp->ypos;
977 r.right = cp->width; r.bottom = STATICHEIGHT;
978 cp->ypos += r.bottom + GAPWITHIN;
979 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
981 rpos = GAPBETWEEN + 2 * (cp->width + GAPBETWEEN) / 3;
982 lwid = rpos - 2*GAPBETWEEN;
983 rwid = cp->width + GAPBETWEEN - rpos;
986 r.left = GAPBETWEEN; r.top = cp->ypos;
987 r.right = lwid; r.bottom = LISTHEIGHT;
988 doctl(cp, r, "LISTBOX",
989 WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL | LBS_HASSTRINGS |
1000 ltext = va_arg(ap, char *);
1002 lid = va_arg(ap, int);
1003 rid = va_arg(ap, int);
1004 r.top = y; r.bottom = STATICHEIGHT;
1005 y += r.bottom + GAPWITHIN;
1006 r.left = rpos; r.right = rwid/2;
1007 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, ltext, lid);
1008 r.left = rpos + r.right; r.right = rwid - r.right;
1009 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE | SS_RIGHT, 0, "", rid);
1014 r.top = y + 2*GAPWITHIN; r.bottom = PUSHBTNHEIGHT;
1015 r.left = rpos; r.right = rwid;
1016 doctl(cp, r, "BUTTON",
1017 WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
1020 cp->ypos += LISTHEIGHT + GAPBETWEEN;
1023 static int GeneralPanelProc (HWND hwnd, UINT msg,
1024 WPARAM wParam, LPARAM lParam) {
1028 HFONT hfont = (HFONT)wParam;
1035 oldfont = SelectObject(hdc, hfont);
1036 GetTextMetrics(hdc, &tm);
1037 units = (tm.tmHeight << 16) | tm.tmAveCharWidth;
1038 SelectObject(hdc, oldfont);
1040 SetWindowLong(hwnd, GWL_USERDATA, units);
1041 SetWindowLong(hwnd, DWL_USER, wParam);
1045 SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
1048 DestroyWindow (hwnd);
1054 static char savedsession[2048];
1056 static int CALLBACK ConnectionProc (HWND hwnd, UINT msg,
1057 WPARAM wParam, LPARAM lParam) {
1060 enum { controlstartvalue = 1000,
1081 /* Accelerators used: [aco] dehlnprstwx */
1082 ctlposinit(&cp, hwnd);
1084 "Host &Name", IDC_HOSTSTATIC, IDC_HOST, 75,
1085 "&Port", IDC_PORTSTATIC, IDC_PORT, 25, NULL);
1086 radioline(&cp, "Protocol:", IDC_PROTSTATIC, 3,
1087 "&Raw", IDC_PROTRAW,
1088 "&Telnet", IDC_PROTTELNET,
1095 sesssaver(&cp, "Stor&ed Sessions",
1096 IDC_SESSSTATIC, IDC_SESSEDIT, IDC_SESSLIST,
1097 "&Load", IDC_SESSLOAD,
1098 "&Save", IDC_SESSSAVE,
1099 "&Delete", IDC_SESSDEL, NULL);
1100 checkbox(&cp, "Close Window on E&xit", IDC_CLOSEEXIT);
1101 checkbox(&cp, "&Warn on Close", IDC_CLOSEWARN);
1103 SetDlgItemText (hwnd, IDC_HOST, cfg.host);
1104 SetDlgItemText (hwnd, IDC_SESSEDIT, savedsession);
1105 SetDlgItemInt (hwnd, IDC_PORT, cfg.port, FALSE);
1106 for (i = 0; i < nsessions; i++)
1107 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_ADDSTRING,
1108 0, (LPARAM) (sessions[i]));
1109 CheckRadioButton (hwnd, IDC_PROTRAW, IDC_PROTSSH,
1110 cfg.protocol==PROT_SSH ? IDC_PROTSSH :
1111 cfg.protocol==PROT_TELNET ? IDC_PROTTELNET : IDC_PROTRAW );
1112 CheckDlgButton (hwnd, IDC_CLOSEEXIT, cfg.close_on_exit);
1113 CheckDlgButton (hwnd, IDC_CLOSEWARN, cfg.warn_on_close);
1117 * Button release should trigger WM_OK if there was a
1118 * previous double click on the session list.
1122 SendMessage (GetParent(hwnd), WM_COMMAND, IDOK, 0);
1125 switch (LOWORD(wParam)) {
1126 case IDC_PROTTELNET:
1129 if (HIWORD(wParam) == BN_CLICKED ||
1130 HIWORD(wParam) == BN_DOUBLECLICKED) {
1131 int i = IsDlgButtonChecked (hwnd, IDC_PROTSSH);
1132 int j = IsDlgButtonChecked (hwnd, IDC_PROTTELNET);
1133 cfg.protocol = i ? PROT_SSH : j ? PROT_TELNET : PROT_RAW ;
1134 if ((cfg.protocol == PROT_SSH && cfg.port == 23) ||
1135 (cfg.protocol == PROT_TELNET && cfg.port == 22)) {
1136 cfg.port = i ? 22 : 23;
1137 SetDlgItemInt (hwnd, IDC_PORT, cfg.port, FALSE);
1142 if (HIWORD(wParam) == EN_CHANGE)
1143 GetDlgItemText (hwnd, IDC_HOST, cfg.host,
1144 sizeof(cfg.host)-1);
1147 if (HIWORD(wParam) == EN_CHANGE)
1148 MyGetDlgItemInt (hwnd, IDC_PORT, &cfg.port);
1151 if (HIWORD(wParam) == BN_CLICKED ||
1152 HIWORD(wParam) == BN_DOUBLECLICKED)
1153 cfg.close_on_exit = IsDlgButtonChecked (hwnd, IDC_CLOSEEXIT);
1156 if (HIWORD(wParam) == BN_CLICKED ||
1157 HIWORD(wParam) == BN_DOUBLECLICKED)
1158 cfg.warn_on_close = IsDlgButtonChecked (hwnd, IDC_CLOSEWARN);
1161 if (HIWORD(wParam) == EN_CHANGE) {
1162 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL,
1164 GetDlgItemText (hwnd, IDC_SESSEDIT,
1165 savedsession, sizeof(savedsession)-1);
1166 savedsession[sizeof(savedsession)-1] = '\0';
1170 if (HIWORD(wParam) == BN_CLICKED ||
1171 HIWORD(wParam) == BN_DOUBLECLICKED) {
1176 GetDlgItemText (hwnd, IDC_SESSEDIT, str, sizeof(str)-1);
1178 int n = SendDlgItemMessage (hwnd, IDC_SESSLIST,
1179 LB_GETCURSEL, 0, 0);
1184 strcpy (str, sessions[n]);
1186 save_settings (str, !!strcmp(str, "Default Settings"));
1187 get_sesslist (FALSE);
1188 get_sesslist (TRUE);
1189 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_RESETCONTENT,
1191 for (i = 0; i < nsessions; i++)
1192 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_ADDSTRING,
1193 0, (LPARAM) (sessions[i]));
1194 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL,
1200 if (LOWORD(wParam) == IDC_SESSLOAD &&
1201 HIWORD(wParam) != BN_CLICKED &&
1202 HIWORD(wParam) != BN_DOUBLECLICKED)
1204 if (LOWORD(wParam) == IDC_SESSLIST &&
1205 HIWORD(wParam) != LBN_DBLCLK)
1208 int n = SendDlgItemMessage (hwnd, IDC_SESSLIST,
1209 LB_GETCURSEL, 0, 0);
1214 load_settings (sessions[n],
1215 !!strcmp(sessions[n], "Default Settings"));
1216 SetDlgItemText (hwnd, IDC_HOST, cfg.host);
1217 SetDlgItemInt (hwnd, IDC_PORT, cfg.port, FALSE);
1218 CheckRadioButton (hwnd, IDC_PROTRAW, IDC_PROTSSH,
1219 (cfg.protocol==PROT_SSH ? IDC_PROTSSH :
1220 cfg.protocol==PROT_TELNET ? IDC_PROTTELNET : IDC_PROTRAW));
1221 CheckDlgButton (hwnd, IDC_CLOSEEXIT, cfg.close_on_exit);
1222 CheckDlgButton (hwnd, IDC_CLOSEWARN, cfg.warn_on_close);
1223 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL,
1226 if (LOWORD(wParam) == IDC_SESSLIST) {
1228 * A double-click on a saved session should
1229 * actually start the session, not just load it.
1230 * Unless it's Default Settings or some other
1231 * host-less set of saved settings.
1240 if (HIWORD(wParam) == BN_CLICKED ||
1241 HIWORD(wParam) == BN_DOUBLECLICKED) {
1242 int n = SendDlgItemMessage (hwnd, IDC_SESSLIST,
1243 LB_GETCURSEL, 0, 0);
1244 if (n == LB_ERR || n == 0) {
1248 del_settings(sessions[n]);
1249 get_sesslist (FALSE);
1250 get_sesslist (TRUE);
1251 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_RESETCONTENT,
1253 for (i = 0; i < nsessions; i++)
1254 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_ADDSTRING,
1255 0, (LPARAM) (sessions[i]));
1256 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL,
1261 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1264 static int CALLBACK KeyboardProc (HWND hwnd, UINT msg,
1265 WPARAM wParam, LPARAM lParam) {
1267 enum { controlstartvalue = 1000,
1293 /* Accelerators used: [aco] 4?ehiklmnprsuvxy */
1294 ctlposinit(&cp, hwnd);
1295 radioline(&cp, "Action of Backspace:", IDC_DELSTATIC, 2,
1296 "Control-&H", IDC_DEL008,
1297 "Control-&? (127)", IDC_DEL127, NULL);
1298 radioline(&cp, "Action of Home and End:", IDC_HOMESTATIC, 2,
1299 "&Standard", IDC_HOMETILDE,
1300 "&rxvt", IDC_HOMERXVT, NULL);
1301 radioline(&cp, "Function key and keypad layout:", IDC_FUNCSTATIC, 3,
1302 "&VT400", IDC_FUNCTILDE,
1303 "&Linux", IDC_FUNCLINUX,
1304 "&Xterm R6", IDC_FUNCXTERM, NULL);
1305 radioline(&cp, "Initial state of cursor keys:", IDC_CURSTATIC, 2,
1306 "&Normal", IDC_CURNORMAL,
1307 "A&pplication", IDC_CURAPPLIC, NULL);
1308 radioline(&cp, "Initial state of numeric keypad:", IDC_KPSTATIC, 3,
1309 "Nor&mal", IDC_KPNORMAL,
1310 "Appl&ication", IDC_KPAPPLIC,
1311 "N&etHack", IDC_KPNH, NULL);
1312 checkbox(&cp, "ALT-F&4 is special (closes window)", IDC_ALTF4);
1313 checkbox(&cp, "ALT-Space is special (S&ystem menu)", IDC_ALTSPACE);
1314 checkbox(&cp, "&Use local terminal line discipline", IDC_LDISCTERM);
1315 checkbox(&cp, "Reset scrollback on &keypress", IDC_SCROLLKEY);
1317 CheckRadioButton (hwnd, IDC_DEL008, IDC_DEL127,
1318 cfg.bksp_is_delete ? IDC_DEL127 : IDC_DEL008);
1319 CheckRadioButton (hwnd, IDC_HOMETILDE, IDC_HOMERXVT,
1320 cfg.rxvt_homeend ? IDC_HOMERXVT : IDC_HOMETILDE);
1321 CheckRadioButton (hwnd, IDC_FUNCTILDE, IDC_FUNCXTERM,
1323 (cfg.funky_type==2 ? IDC_FUNCXTERM
1326 CheckRadioButton (hwnd, IDC_CURNORMAL, IDC_CURAPPLIC,
1327 cfg.app_cursor ? IDC_CURAPPLIC : IDC_CURNORMAL);
1328 CheckRadioButton (hwnd, IDC_KPNORMAL, IDC_KPNH,
1329 cfg.nethack_keypad ? IDC_KPNH :
1330 cfg.app_keypad ? IDC_KPAPPLIC : IDC_KPNORMAL);
1331 CheckDlgButton (hwnd, IDC_ALTF4, cfg.alt_f4);
1332 CheckDlgButton (hwnd, IDC_ALTSPACE, cfg.alt_space);
1333 CheckDlgButton (hwnd, IDC_LDISCTERM, cfg.ldisc_term);
1334 CheckDlgButton (hwnd, IDC_SCROLLKEY, cfg.scroll_on_key);
1337 if (HIWORD(wParam) == BN_CLICKED ||
1338 HIWORD(wParam) == BN_DOUBLECLICKED)
1339 switch (LOWORD(wParam)) {
1342 cfg.bksp_is_delete = IsDlgButtonChecked (hwnd, IDC_DEL127);
1346 cfg.rxvt_homeend = IsDlgButtonChecked (hwnd, IDC_HOMERXVT);
1353 cfg.funky_type = IsDlgButtonChecked (hwnd, IDC_FUNCLINUX);
1357 cfg.app_keypad = IsDlgButtonChecked (hwnd, IDC_KPAPPLIC);
1358 cfg.nethack_keypad = FALSE;
1361 cfg.app_keypad = FALSE;
1362 cfg.nethack_keypad = TRUE;
1366 cfg.app_cursor = IsDlgButtonChecked (hwnd, IDC_CURAPPLIC);
1369 if (HIWORD(wParam) == BN_CLICKED ||
1370 HIWORD(wParam) == BN_DOUBLECLICKED)
1371 cfg.alt_f4 = IsDlgButtonChecked (hwnd, IDC_ALTF4);
1374 if (HIWORD(wParam) == BN_CLICKED ||
1375 HIWORD(wParam) == BN_DOUBLECLICKED)
1376 cfg.alt_space = IsDlgButtonChecked (hwnd, IDC_ALTSPACE);
1379 if (HIWORD(wParam) == BN_CLICKED ||
1380 HIWORD(wParam) == BN_DOUBLECLICKED)
1381 cfg.ldisc_term = IsDlgButtonChecked (hwnd, IDC_LDISCTERM);
1384 if (HIWORD(wParam) == BN_CLICKED ||
1385 HIWORD(wParam) == BN_DOUBLECLICKED)
1386 cfg.scroll_on_key = IsDlgButtonChecked (hwnd, IDC_SCROLLKEY);
1390 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1393 static void fmtfont (char *buf) {
1394 sprintf (buf, "Font: %s, ", cfg.font);
1396 strcat(buf, "bold, ");
1397 if (cfg.fontheight == 0)
1398 strcat (buf, "default height");
1400 sprintf (buf+strlen(buf), "%d-%s",
1401 (cfg.fontheight < 0 ? -cfg.fontheight : cfg.fontheight),
1402 (cfg.fontheight < 0 ? "pixel" : "point"));
1405 static int CALLBACK TerminalProc (HWND hwnd, UINT msg,
1406 WPARAM wParam, LPARAM lParam) {
1410 char fontstatic[256];
1411 enum { controlstartvalue = 1000,
1431 /* Accelerators used: [aco] dghlmnprsw */
1432 ctlposinit(&cp, hwnd);
1434 "&Rows", IDC_ROWSSTATIC, IDC_ROWSEDIT, 33,
1435 "Colu&mns", IDC_COLSSTATIC, IDC_COLSEDIT, 33,
1436 "&Scrollback", IDC_SAVESTATIC, IDC_SAVEEDIT, 33,
1438 staticbtn(&cp, "", IDC_FONTSTATIC, "C&hange...", IDC_CHOOSEFONT);
1439 checkbox(&cp, "Auto &wrap mode initially on", IDC_WRAPMODE);
1440 checkbox(&cp, "&DEC Origin Mode initially on", IDC_DECOM);
1441 checkbox(&cp, "Implicit CR in every &LF", IDC_LFHASCR);
1442 checkbox(&cp, "Bee&p enabled", IDC_BEEP);
1443 checkbox(&cp, "Use Back&ground colour erase", IDC_BCE);
1444 checkbox(&cp, "Enable bli&nking text", IDC_BLINKTEXT);
1446 CheckDlgButton (hwnd, IDC_WRAPMODE, cfg.wrap_mode);
1447 CheckDlgButton (hwnd, IDC_DECOM, cfg.dec_om);
1448 CheckDlgButton (hwnd, IDC_LFHASCR, cfg.lfhascr);
1449 SetDlgItemInt (hwnd, IDC_ROWSEDIT, cfg.height, FALSE);
1450 SetDlgItemInt (hwnd, IDC_COLSEDIT, cfg.width, FALSE);
1451 SetDlgItemInt (hwnd, IDC_SAVEEDIT, cfg.savelines, FALSE);
1452 fmtfont (fontstatic);
1453 SetDlgItemText (hwnd, IDC_FONTSTATIC, fontstatic);
1454 CheckDlgButton (hwnd, IDC_BEEP, cfg.beep);
1455 CheckDlgButton (hwnd, IDC_BCE, cfg.bce);
1456 CheckDlgButton (hwnd, IDC_BLINKTEXT, cfg.blinktext);
1459 switch (LOWORD(wParam)) {
1461 if (HIWORD(wParam) == BN_CLICKED ||
1462 HIWORD(wParam) == BN_DOUBLECLICKED)
1463 cfg.wrap_mode = IsDlgButtonChecked (hwnd, IDC_WRAPMODE);
1466 if (HIWORD(wParam) == BN_CLICKED ||
1467 HIWORD(wParam) == BN_DOUBLECLICKED)
1468 cfg.dec_om = IsDlgButtonChecked (hwnd, IDC_DECOM);
1471 if (HIWORD(wParam) == BN_CLICKED ||
1472 HIWORD(wParam) == BN_DOUBLECLICKED)
1473 cfg.lfhascr = IsDlgButtonChecked (hwnd, IDC_LFHASCR);
1476 if (HIWORD(wParam) == EN_CHANGE)
1477 MyGetDlgItemInt (hwnd, IDC_ROWSEDIT, &cfg.height);
1480 if (HIWORD(wParam) == EN_CHANGE)
1481 MyGetDlgItemInt (hwnd, IDC_COLSEDIT, &cfg.width);
1484 if (HIWORD(wParam) == EN_CHANGE)
1485 MyGetDlgItemInt (hwnd, IDC_SAVEEDIT, &cfg.savelines);
1487 case IDC_CHOOSEFONT:
1488 lf.lfHeight = cfg.fontheight;
1489 lf.lfWidth = lf.lfEscapement = lf.lfOrientation = 0;
1490 lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = 0;
1491 lf.lfWeight = (cfg.fontisbold ? FW_BOLD : 0);
1492 lf.lfCharSet = cfg.fontcharset;
1493 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
1494 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1495 lf.lfQuality = DEFAULT_QUALITY;
1496 lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
1497 strncpy (lf.lfFaceName, cfg.font, sizeof(lf.lfFaceName)-1);
1498 lf.lfFaceName[sizeof(lf.lfFaceName)-1] = '\0';
1500 cf.lStructSize = sizeof(cf);
1501 cf.hwndOwner = hwnd;
1503 cf.Flags = CF_FIXEDPITCHONLY | CF_FORCEFONTEXIST |
1504 CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
1506 if (ChooseFont (&cf)) {
1507 strncpy (cfg.font, lf.lfFaceName, sizeof(cfg.font)-1);
1508 cfg.font[sizeof(cfg.font)-1] = '\0';
1509 cfg.fontisbold = (lf.lfWeight == FW_BOLD);
1510 cfg.fontcharset = lf.lfCharSet;
1511 cfg.fontheight = lf.lfHeight;
1512 fmtfont (fontstatic);
1513 SetDlgItemText (hwnd, IDC_FONTSTATIC, fontstatic);
1517 if (HIWORD(wParam) == BN_CLICKED ||
1518 HIWORD(wParam) == BN_DOUBLECLICKED)
1519 cfg.beep = IsDlgButtonChecked (hwnd, IDC_BEEP);
1522 if (HIWORD(wParam) == BN_CLICKED ||
1523 HIWORD(wParam) == BN_DOUBLECLICKED)
1524 cfg.blinktext = IsDlgButtonChecked (hwnd, IDC_BLINKTEXT);
1527 if (HIWORD(wParam) == BN_CLICKED ||
1528 HIWORD(wParam) == BN_DOUBLECLICKED)
1529 cfg.bce = IsDlgButtonChecked (hwnd, IDC_BCE);
1534 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1537 static int CALLBACK WindowProc (HWND hwnd, UINT msg,
1538 WPARAM wParam, LPARAM lParam) {
1540 enum { controlstartvalue = 1000,
1551 /* Accelerators used: [aco] bikty */
1552 ctlposinit(&cp, hwnd);
1554 "Initial window &title:", IDC_WINTITLE, IDC_WINEDIT, 100,
1556 checkbox(&cp, "Avoid ever using &icon title", IDC_WINNAME);
1557 checkbox(&cp, "&Blinking cursor", IDC_BLINKCUR);
1558 checkbox(&cp, "Displa&y scrollbar", IDC_SCROLLBAR);
1559 checkbox(&cp, "Loc&k Window size", IDC_LOCKSIZE);
1561 SetDlgItemText (hwnd, IDC_WINEDIT, cfg.wintitle);
1562 CheckDlgButton (hwnd, IDC_WINNAME, cfg.win_name_always);
1563 CheckDlgButton (hwnd, IDC_BLINKCUR, cfg.blink_cur);
1564 CheckDlgButton (hwnd, IDC_SCROLLBAR, cfg.scrollbar);
1565 CheckDlgButton (hwnd, IDC_LOCKSIZE, cfg.locksize);
1568 switch (LOWORD(wParam)) {
1570 if (HIWORD(wParam) == BN_CLICKED ||
1571 HIWORD(wParam) == BN_DOUBLECLICKED)
1572 cfg.win_name_always = IsDlgButtonChecked (hwnd, IDC_WINNAME);
1575 if (HIWORD(wParam) == BN_CLICKED ||
1576 HIWORD(wParam) == BN_DOUBLECLICKED)
1577 cfg.blink_cur = IsDlgButtonChecked (hwnd, IDC_BLINKCUR);
1580 if (HIWORD(wParam) == BN_CLICKED ||
1581 HIWORD(wParam) == BN_DOUBLECLICKED)
1582 cfg.scrollbar = IsDlgButtonChecked (hwnd, IDC_SCROLLBAR);
1585 if (HIWORD(wParam) == BN_CLICKED ||
1586 HIWORD(wParam) == BN_DOUBLECLICKED)
1587 cfg.locksize = IsDlgButtonChecked (hwnd, IDC_LOCKSIZE);
1590 if (HIWORD(wParam) == EN_CHANGE)
1591 GetDlgItemText (hwnd, IDC_WINEDIT, cfg.wintitle,
1592 sizeof(cfg.wintitle)-1);
1597 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1600 static int CALLBACK TelnetProc (HWND hwnd, UINT msg,
1601 WPARAM wParam, LPARAM lParam) {
1604 enum { controlstartvalue = 1000,
1626 /* Accelerators used: [aco] bdflrstuv */
1627 ctlposinit(&cp, hwnd);
1628 staticedit(&cp, "Terminal-&type string", IDC_TTSTATIC, IDC_TTEDIT);
1629 staticedit(&cp, "Terminal-&speed string", IDC_TSSTATIC, IDC_TSEDIT);
1630 staticedit(&cp, "Auto-login &username", IDC_LOGSTATIC, IDC_LOGEDIT);
1631 envsetter(&cp, "Environment variables:", IDC_ENVSTATIC,
1632 "&Variable", IDC_VARSTATIC, IDC_VAREDIT,
1633 "Va&lue", IDC_VALSTATIC, IDC_VALEDIT,
1635 "A&dd", IDC_ENVADD, "&Remove", IDC_ENVREMOVE);
1636 radioline(&cp, "Handling of OLD_ENVIRON ambiguity:", IDC_EMSTATIC, 2,
1637 "&BSD (commonplace)", IDC_EMBSD,
1638 "R&FC 1408 (unusual)", IDC_EMRFC, NULL);
1640 SetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype);
1641 SetDlgItemText (hwnd, IDC_TSEDIT, cfg.termspeed);
1642 SetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username);
1644 char *p = cfg.environmt;
1646 SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_ADDSTRING, 0,
1651 CheckRadioButton (hwnd, IDC_EMBSD, IDC_EMRFC,
1652 cfg.rfc_environ ? IDC_EMRFC : IDC_EMBSD);
1655 switch (LOWORD(wParam)) {
1657 if (HIWORD(wParam) == EN_CHANGE)
1658 GetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype,
1659 sizeof(cfg.termtype)-1);
1662 if (HIWORD(wParam) == EN_CHANGE)
1663 GetDlgItemText (hwnd, IDC_TSEDIT, cfg.termspeed,
1664 sizeof(cfg.termspeed)-1);
1667 if (HIWORD(wParam) == EN_CHANGE)
1668 GetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username,
1669 sizeof(cfg.username)-1);
1673 cfg.rfc_environ = IsDlgButtonChecked (hwnd, IDC_EMRFC);
1676 if (HIWORD(wParam) == BN_CLICKED ||
1677 HIWORD(wParam) == BN_DOUBLECLICKED) {
1678 char str[sizeof(cfg.environmt)];
1680 GetDlgItemText (hwnd, IDC_VAREDIT, str, sizeof(str)-1);
1685 p = str + strlen(str);
1687 GetDlgItemText (hwnd, IDC_VALEDIT, p, sizeof(str)-1-(p-str));
1697 if ((p-cfg.environmt) + strlen(str) + 2 < sizeof(cfg.environmt)) {
1699 p[strlen(str)+1] = '\0';
1700 SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_ADDSTRING,
1702 SetDlgItemText (hwnd, IDC_VAREDIT, "");
1703 SetDlgItemText (hwnd, IDC_VALEDIT, "");
1705 MessageBox(hwnd, "Environment too big", "PuTTY Error",
1706 MB_OK | MB_ICONERROR);
1711 if (HIWORD(wParam) != BN_CLICKED &&
1712 HIWORD(wParam) != BN_DOUBLECLICKED)
1714 i = SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_GETCURSEL, 0, 0);
1720 SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_DELETESTRING,
1747 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1750 static int CALLBACK SshProc (HWND hwnd, UINT msg,
1751 WPARAM wParam, LPARAM lParam) {
1754 char filename[sizeof(cfg.keyfile)];
1755 enum { controlstartvalue = 1000,
1779 /* Accelerators used: [aco] 123abdkmprtuw */
1780 ctlposinit(&cp, hwnd);
1781 staticedit(&cp, "Terminal-&type string", IDC_TTSTATIC, IDC_TTEDIT);
1782 staticedit(&cp, "Auto-login &username", IDC_LOGSTATIC, IDC_LOGEDIT);
1784 "&Remote command:", IDC_CMDSTATIC, IDC_CMDEDIT, 100,
1786 checkbox(&cp, "Don't allocate a &pseudo-terminal", IDC_NOPTY);
1787 checkbox(&cp, "Atte&mpt TIS or CryptoCard authentication",
1789 checkbox(&cp, "Allow &agent forwarding", IDC_AGENTFWD);
1790 editbutton(&cp, "Private &key file for authentication:",
1791 IDC_PKSTATIC, IDC_PKEDIT, "Bro&wse...", IDC_PKBUTTON);
1792 radioline(&cp, "Preferred SSH protocol version:",
1793 IDC_SSHPROTSTATIC, 2,
1794 "&1", IDC_SSHPROT1, "&2", IDC_SSHPROT2, NULL);
1795 radioline(&cp, "Preferred encryption algorithm:", IDC_CIPHERSTATIC, 3,
1796 "&3DES", IDC_CIPHER3DES,
1797 "&Blowfish", IDC_CIPHERBLOWF,
1798 "&DES", IDC_CIPHERDES, NULL);
1800 SetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype);
1801 SetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username);
1802 CheckDlgButton (hwnd, IDC_NOPTY, cfg.nopty);
1803 CheckDlgButton (hwnd, IDC_AGENTFWD, cfg.agentfwd);
1804 CheckRadioButton (hwnd, IDC_CIPHER3DES, IDC_CIPHERDES,
1805 cfg.cipher == CIPHER_BLOWFISH ? IDC_CIPHERBLOWF :
1806 cfg.cipher == CIPHER_DES ? IDC_CIPHERDES :
1808 CheckRadioButton (hwnd, IDC_SSHPROT1, IDC_SSHPROT2,
1809 cfg.sshprot == 1 ? IDC_SSHPROT1 : IDC_SSHPROT2);
1810 CheckDlgButton (hwnd, IDC_AUTHTIS, cfg.try_tis_auth);
1811 SetDlgItemText (hwnd, IDC_PKEDIT, cfg.keyfile);
1812 SetDlgItemText (hwnd, IDC_CMDEDIT, cfg.remote_cmd);
1815 switch (LOWORD(wParam)) {
1817 if (HIWORD(wParam) == EN_CHANGE)
1818 GetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype,
1819 sizeof(cfg.termtype)-1);
1822 if (HIWORD(wParam) == EN_CHANGE)
1823 GetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username,
1824 sizeof(cfg.username)-1);
1827 if (HIWORD(wParam) == BN_CLICKED ||
1828 HIWORD(wParam) == BN_DOUBLECLICKED)
1829 cfg.nopty = IsDlgButtonChecked (hwnd, IDC_NOPTY);
1832 if (HIWORD(wParam) == BN_CLICKED ||
1833 HIWORD(wParam) == BN_DOUBLECLICKED)
1834 cfg.agentfwd = IsDlgButtonChecked (hwnd, IDC_AGENTFWD);
1836 case IDC_CIPHER3DES:
1837 case IDC_CIPHERBLOWF:
1839 if (HIWORD(wParam) == BN_CLICKED ||
1840 HIWORD(wParam) == BN_DOUBLECLICKED) {
1841 if (IsDlgButtonChecked (hwnd, IDC_CIPHER3DES))
1842 cfg.cipher = CIPHER_3DES;
1843 else if (IsDlgButtonChecked (hwnd, IDC_CIPHERBLOWF))
1844 cfg.cipher = CIPHER_BLOWFISH;
1845 else if (IsDlgButtonChecked (hwnd, IDC_CIPHERDES))
1846 cfg.cipher = CIPHER_DES;
1851 if (HIWORD(wParam) == BN_CLICKED ||
1852 HIWORD(wParam) == BN_DOUBLECLICKED) {
1853 if (IsDlgButtonChecked (hwnd, IDC_SSHPROT1))
1855 else if (IsDlgButtonChecked (hwnd, IDC_SSHPROT2))
1860 if (HIWORD(wParam) == BN_CLICKED ||
1861 HIWORD(wParam) == BN_DOUBLECLICKED)
1862 cfg.try_tis_auth = IsDlgButtonChecked (hwnd, IDC_AUTHTIS);
1865 if (HIWORD(wParam) == EN_CHANGE)
1866 GetDlgItemText (hwnd, IDC_PKEDIT, cfg.keyfile,
1867 sizeof(cfg.keyfile)-1);
1870 if (HIWORD(wParam) == EN_CHANGE)
1871 GetDlgItemText (hwnd, IDC_CMDEDIT, cfg.remote_cmd,
1872 sizeof(cfg.remote_cmd)-1);
1876 * FIXME: this crashes. Find out why.
1878 memset(&of, 0, sizeof(of));
1879 #ifdef OPENFILENAME_SIZE_VERSION_400
1880 of.lStructSize = OPENFILENAME_SIZE_VERSION_400;
1882 of.lStructSize = sizeof(of);
1884 of.hwndOwner = hwnd;
1885 of.lpstrFilter = "All Files\0*\0\0\0";
1886 of.lpstrCustomFilter = NULL;
1887 of.nFilterIndex = 1;
1888 of.lpstrFile = filename; strcpy(filename, cfg.keyfile);
1889 of.nMaxFile = sizeof(filename);
1890 of.lpstrFileTitle = NULL;
1891 of.lpstrInitialDir = NULL;
1892 of.lpstrTitle = "Select Public Key File";
1894 if (GetOpenFileName(&of)) {
1895 strcpy(cfg.keyfile, filename);
1896 SetDlgItemText (hwnd, IDC_PKEDIT, cfg.keyfile);
1902 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1905 static int CALLBACK SelectionProc (HWND hwnd, UINT msg,
1906 WPARAM wParam, LPARAM lParam) {
1909 enum { controlstartvalue = 1000,
1922 /* Accelerators used: [aco] stwx */
1923 ctlposinit(&cp, hwnd);
1924 radiobig(&cp, "Action of mouse buttons:", IDC_MBSTATIC,
1925 "&Windows (Right pastes, Middle extends)", IDC_MBWINDOWS,
1926 "&xterm (Right extends, Middle pastes)", IDC_MBXTERM,
1928 charclass(&cp, "Character classes:", IDC_CCSTATIC, IDC_CCLIST,
1929 "&Set", IDC_CCSET, IDC_CCEDIT,
1930 "&to class", IDC_CCSTATIC2);
1932 CheckRadioButton (hwnd, IDC_MBWINDOWS, IDC_MBXTERM,
1933 cfg.mouse_is_xterm ? IDC_MBXTERM : IDC_MBWINDOWS);
1935 static int tabs[4] = {25, 61, 96, 128};
1936 SendDlgItemMessage (hwnd, IDC_CCLIST, LB_SETTABSTOPS, 4,
1939 for (i=0; i<256; i++) {
1941 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
1942 (i>=0x21 && i != 0x7F) ? i : ' ',
1944 SendDlgItemMessage (hwnd, IDC_CCLIST, LB_ADDSTRING, 0,
1949 switch (LOWORD(wParam)) {
1952 cfg.mouse_is_xterm = IsDlgButtonChecked (hwnd, IDC_MBXTERM);
1958 int n = GetDlgItemInt (hwnd, IDC_CCEDIT, &ok, FALSE);
1963 for (i=0; i<256; i++)
1964 if (SendDlgItemMessage (hwnd, IDC_CCLIST, LB_GETSEL,
1967 cfg.wordness[i] = n;
1968 SendDlgItemMessage (hwnd, IDC_CCLIST,
1969 LB_DELETESTRING, i, 0);
1970 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
1971 (i>=0x21 && i != 0x7F) ? i : ' ',
1973 SendDlgItemMessage (hwnd, IDC_CCLIST,
1983 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1986 static int CALLBACK ColourProc (HWND hwnd, UINT msg,
1987 WPARAM wParam, LPARAM lParam) {
1988 static const char *const colours[] = {
1989 "Default Foreground", "Default Bold Foreground",
1990 "Default Background", "Default Bold Background",
1991 "Cursor Text", "Cursor Colour",
1992 "ANSI Black", "ANSI Black Bold",
1993 "ANSI Red", "ANSI Red Bold",
1994 "ANSI Green", "ANSI Green Bold",
1995 "ANSI Yellow", "ANSI Yellow Bold",
1996 "ANSI Blue", "ANSI Blue Bold",
1997 "ANSI Magenta", "ANSI Magenta Bold",
1998 "ANSI Cyan", "ANSI Cyan Bold",
1999 "ANSI White", "ANSI White Bold"
2001 static const int permanent[] = {
2002 TRUE, FALSE, TRUE, FALSE, TRUE, TRUE,
2003 TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE,
2004 TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE
2007 enum { controlstartvalue = 1000,
2023 /* Accelerators used: [aco] bmlu */
2024 ctlposinit(&cp, hwnd);
2025 checkbox(&cp, "&Bolded text is a different colour", IDC_BOLDCOLOUR);
2026 checkbox(&cp, "Attempt to use &logical palettes", IDC_PALETTE);
2027 colouredit(&cp, "Select a colo&ur and click to modify it:",
2028 IDC_STATIC, IDC_LIST,
2029 "&Modify...", IDC_CHANGE,
2030 "Red:", IDC_RSTATIC, IDC_RVALUE,
2031 "Green:", IDC_GSTATIC, IDC_GVALUE,
2032 "Blue:", IDC_BSTATIC, IDC_BVALUE, NULL);
2034 CheckDlgButton (hwnd, IDC_BOLDCOLOUR, cfg.bold_colour);
2035 CheckDlgButton (hwnd, IDC_PALETTE, cfg.try_palette);
2038 for (i=0; i<22; i++)
2039 if (cfg.bold_colour || permanent[i])
2040 SendDlgItemMessage (hwnd, IDC_LIST, LB_ADDSTRING, 0,
2041 (LPARAM) colours[i]);
2043 SendDlgItemMessage (hwnd, IDC_LIST, LB_SETCURSEL, 0, 0);
2044 SetDlgItemInt (hwnd, IDC_RVALUE, cfg.colours[0][0], FALSE);
2045 SetDlgItemInt (hwnd, IDC_GVALUE, cfg.colours[0][1], FALSE);
2046 SetDlgItemInt (hwnd, IDC_BVALUE, cfg.colours[0][2], FALSE);
2049 switch (LOWORD(wParam)) {
2050 case IDC_BOLDCOLOUR:
2051 if (HIWORD(wParam) == BN_CLICKED ||
2052 HIWORD(wParam) == BN_DOUBLECLICKED) {
2054 cfg.bold_colour = IsDlgButtonChecked (hwnd, IDC_BOLDCOLOUR);
2055 n = SendDlgItemMessage (hwnd, IDC_LIST, LB_GETCOUNT, 0, 0);
2056 if (cfg.bold_colour && n!=22) {
2057 for (i=0; i<22; i++)
2059 SendDlgItemMessage (hwnd, IDC_LIST,
2061 (LPARAM) colours[i]);
2062 } else if (!cfg.bold_colour && n!=12) {
2065 SendDlgItemMessage (hwnd, IDC_LIST,
2066 LB_DELETESTRING, i, 0);
2071 if (HIWORD(wParam) == BN_CLICKED ||
2072 HIWORD(wParam) == BN_DOUBLECLICKED)
2073 cfg.try_palette = IsDlgButtonChecked (hwnd, IDC_PALETTE);
2076 if (HIWORD(wParam) == LBN_DBLCLK ||
2077 HIWORD(wParam) == LBN_SELCHANGE) {
2078 int i = SendDlgItemMessage (hwnd, IDC_LIST, LB_GETCURSEL,
2080 if (!cfg.bold_colour)
2081 i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
2082 SetDlgItemInt (hwnd, IDC_RVALUE, cfg.colours[i][0], FALSE);
2083 SetDlgItemInt (hwnd, IDC_GVALUE, cfg.colours[i][1], FALSE);
2084 SetDlgItemInt (hwnd, IDC_BVALUE, cfg.colours[i][2], FALSE);
2088 if (HIWORD(wParam) == BN_CLICKED ||
2089 HIWORD(wParam) == BN_DOUBLECLICKED) {
2090 static CHOOSECOLOR cc;
2091 static DWORD custom[16] = {0}; /* zero initialisers */
2092 int i = SendDlgItemMessage (hwnd, IDC_LIST, LB_GETCURSEL,
2094 if (!cfg.bold_colour)
2095 i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
2096 cc.lStructSize = sizeof(cc);
2097 cc.hwndOwner = hwnd;
2098 cc.hInstance = (HWND)hinst;
2099 cc.lpCustColors = custom;
2100 cc.rgbResult = RGB (cfg.colours[i][0], cfg.colours[i][1],
2102 cc.Flags = CC_FULLOPEN | CC_RGBINIT;
2103 if (ChooseColor(&cc)) {
2105 (unsigned char) (cc.rgbResult & 0xFF);
2107 (unsigned char) (cc.rgbResult >> 8) & 0xFF;
2109 (unsigned char) (cc.rgbResult >> 16) & 0xFF;
2110 SetDlgItemInt (hwnd, IDC_RVALUE, cfg.colours[i][0],
2112 SetDlgItemInt (hwnd, IDC_GVALUE, cfg.colours[i][1],
2114 SetDlgItemInt (hwnd, IDC_BVALUE, cfg.colours[i][2],
2122 return GeneralPanelProc (hwnd, msg, wParam, lParam);
2125 static int CALLBACK TranslationProc (HWND hwnd, UINT msg,
2126 WPARAM wParam, LPARAM lParam) {
2128 enum { controlstartvalue = 1000,
2143 /* Accelerators used: [aco] beiknpsx */
2144 ctlposinit(&cp, hwnd);
2146 "Handling of VT100 line drawing characters:", IDC_VTSTATIC,
2147 "Font has &XWindows encoding", IDC_VTXWINDOWS,
2148 "Use font in &both ANSI and OEM modes", IDC_VTOEMANSI,
2149 "Use font in O&EM mode only", IDC_VTOEMONLY,
2150 "&Poor man's line drawing (""+"", ""-"" and ""|"")",
2151 IDC_VTPOORMAN, NULL);
2153 "Character set translation:", IDC_XLATSTATIC,
2154 "&None", IDC_NOXLAT,
2155 "&KOI8 / Win-1251", IDC_KOI8WIN1251,
2156 "&ISO-8859-2 / Win-1250", IDC_88592WIN1250, NULL);
2157 checkbox(&cp, "CAP&S LOCK acts as cyrillic switch", IDC_CAPSLOCKCYR);
2159 CheckRadioButton (hwnd, IDC_NOXLAT, IDC_88592WIN1250,
2160 cfg.xlat_88592w1250 ? IDC_88592WIN1250 :
2161 cfg.xlat_enablekoiwin ? IDC_KOI8WIN1251 :
2163 CheckDlgButton (hwnd, IDC_CAPSLOCKCYR, cfg.xlat_capslockcyr);
2164 CheckRadioButton (hwnd, IDC_VTXWINDOWS, IDC_VTPOORMAN,
2165 cfg.vtmode == VT_XWINDOWS ? IDC_VTXWINDOWS :
2166 cfg.vtmode == VT_OEMANSI ? IDC_VTOEMANSI :
2167 cfg.vtmode == VT_OEMONLY ? IDC_VTOEMONLY :
2170 switch (LOWORD(wParam)) {
2172 case IDC_KOI8WIN1251:
2173 case IDC_88592WIN1250:
2174 cfg.xlat_enablekoiwin =
2175 IsDlgButtonChecked (hwnd, IDC_KOI8WIN1251);
2176 cfg.xlat_88592w1250 =
2177 IsDlgButtonChecked (hwnd, IDC_88592WIN1250);
2179 case IDC_CAPSLOCKCYR:
2180 if (HIWORD(wParam) == BN_CLICKED ||
2181 HIWORD(wParam) == BN_DOUBLECLICKED) {
2182 cfg.xlat_capslockcyr =
2183 IsDlgButtonChecked (hwnd, IDC_CAPSLOCKCYR);
2186 case IDC_VTXWINDOWS:
2191 (IsDlgButtonChecked (hwnd, IDC_VTXWINDOWS) ? VT_XWINDOWS :
2192 IsDlgButtonChecked (hwnd, IDC_VTOEMANSI) ? VT_OEMANSI :
2193 IsDlgButtonChecked (hwnd, IDC_VTOEMONLY) ? VT_OEMONLY :
2198 return GeneralPanelProc (hwnd, msg, wParam, lParam);
2201 static DLGPROC panelproc[NPANELS] = {
2202 ConnectionProc, KeyboardProc, TerminalProc, WindowProc,
2203 TelnetProc, SshProc, SelectionProc, ColourProc, TranslationProc
2206 static char *names[NPANELS] = {
2207 "Connection", "Keyboard", "Terminal", "Window", "Telnet",
2208 "SSH", "Selection", "Colours", "Translation"
2211 static int mainp[MAIN_NPANELS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8};
2212 static int reconfp[RECONF_NPANELS] = { 1, 2, 3, 6, 7, 8};
2214 static HWND makesubdialog(HWND hwnd, int x, int y, int w, int h, int n) {
2218 r.left = x; r.top = y;
2219 r.right = r.left + w; r.bottom = r.top + h;
2220 MapDialogRect(hwnd, &r);
2221 ret = CreateWindowEx(WS_EX_CONTROLPARENT,
2222 WC_DIALOG, "", /* no title */
2223 WS_CHILD | WS_VISIBLE | DS_SETFONT,
2225 r.right-r.left, r.bottom-r.top,
2226 hwnd, (HMENU)IDC_SUBDLG,
2228 SetWindowLong (ret, DWL_DLGPROC, (LONG)panelproc[n]);
2229 font = SendMessage(hwnd, WM_GETFONT, 0, 0);
2230 SendMessage (ret, WM_SETFONT, font, MAKELPARAM(0, 0));
2231 SendMessage (ret, WM_INITDIALOG, 0, 0);
2235 static int GenericMainDlgProc (HWND hwnd, UINT msg,
2236 WPARAM wParam, LPARAM lParam,
2237 int npanels, int *panelnums, HWND *page) {
2242 { /* centre the window */
2245 hw = GetDesktopWindow();
2246 if (GetWindowRect (hw, &rs) && GetWindowRect (hwnd, &rd))
2247 MoveWindow (hwnd, (rs.right + rs.left + rd.left - rd.right)/2,
2248 (rs.bottom + rs.top + rd.top - rd.bottom)/2,
2249 rd.right-rd.left, rd.bottom-rd.top, TRUE);
2253 r.left = 3; r.right = r.left + 174;
2254 r.top = 3; r.bottom = r.top + 193;
2255 MapDialogRect(hwnd, &r);
2256 tabctl = CreateWindowEx(0, WC_TABCONTROL, "",
2257 WS_CHILD | WS_VISIBLE |
2258 WS_TABSTOP | TCS_MULTILINE,
2260 r.right-r.left, r.bottom-r.top,
2261 hwnd, (HMENU)IDC_TAB, hinst, NULL);
2265 ctlposinit2(&cp, hwnd);
2266 ersatztab(&cp, "Category:", IDC_TABSTATIC1, IDC_TABLIST,
2269 WPARAM font = SendMessage(hwnd, WM_GETFONT, 0, 0);
2270 SendMessage(tabctl, WM_SETFONT, font, MAKELPARAM(TRUE, 0));
2274 if (tabctl) { /* initialise the tab control */
2278 for (i=0; i<npanels; i++) {
2279 tab.mask = TCIF_TEXT;
2280 tab.pszText = names[panelnums[i]];
2281 TabCtrl_InsertItem (tabctl, i, &tab);
2286 for (i=0; i<npanels; i++) {
2287 SendDlgItemMessage(hwnd, IDC_TABLIST, CB_ADDSTRING,
2288 0, (LPARAM)names[panelnums[i]]);
2290 SendDlgItemMessage(hwnd, IDC_TABLIST, CB_SETCURSEL, 0, 0);
2292 *page = makesubdialog(hwnd, 6, 30, 168, 163, panelnums[0]);
2296 if (LOWORD(wParam) == IDC_TAB &&
2297 ((LPNMHDR)lParam)->code == TCN_SELCHANGE) {
2298 int i = TabCtrl_GetCurSel(((LPNMHDR)lParam)->hwndFrom);
2300 DestroyWindow (*page);
2301 *page = makesubdialog(hwnd, 6, 30, 168, 163, panelnums[i]);
2302 SetFocus (((LPNMHDR)lParam)->hwndFrom); /* ensure focus stays */
2307 switch (LOWORD(wParam)) {
2309 if (HIWORD(wParam) == CBN_SELCHANGE) {
2310 HWND tablist = GetDlgItem (hwnd, IDC_TABLIST);
2311 int i = SendMessage (tablist, CB_GETCURSEL, 0, 0);
2313 DestroyWindow (*page);
2314 *page = makesubdialog(hwnd, 6, 30, 168, 163, panelnums[i]);
2315 SetFocus(tablist); /* ensure focus stays */
2321 EndDialog (hwnd, 1);
2326 EndDialog (hwnd, 0);
2331 EndDialog (hwnd, 0);
2334 /* Grrr Explorer will maximize Dialogs! */
2336 if (wParam == SIZE_MAXIMIZED)
2343 static int CALLBACK MainDlgProc (HWND hwnd, UINT msg,
2344 WPARAM wParam, LPARAM lParam) {
2345 static HWND page = NULL;
2347 if (msg == WM_COMMAND && LOWORD(wParam) == IDOK) {
2349 if (msg == WM_COMMAND && LOWORD(wParam) == IDC_ABOUT) {
2350 EnableWindow(hwnd, 0);
2351 DialogBox(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
2352 GetParent(hwnd), AboutProc);
2353 EnableWindow(hwnd, 1);
2354 SetActiveWindow(hwnd);
2356 return GenericMainDlgProc (hwnd, msg, wParam, lParam,
2357 MAIN_NPANELS, mainp, &page);
2360 static int CALLBACK ReconfDlgProc (HWND hwnd, UINT msg,
2361 WPARAM wParam, LPARAM lParam) {
2363 return GenericMainDlgProc (hwnd, msg, wParam, lParam,
2364 RECONF_NPANELS, reconfp, &page);
2367 void get_sesslist(int allocate) {
2368 static char otherbuf[2048];
2369 static char *buffer;
2370 int buflen, bufsize, i;
2376 if ((handle = enum_settings_start()) == NULL)
2379 buflen = bufsize = 0;
2382 ret = enum_settings_next(handle, otherbuf, sizeof(otherbuf));
2384 int len = strlen(otherbuf)+1;
2385 if (bufsize < buflen+len) {
2386 bufsize = buflen + len + 2048;
2387 buffer = srealloc(buffer, bufsize);
2389 strcpy(buffer+buflen, otherbuf);
2390 buflen += strlen(buffer+buflen)+1;
2393 enum_settings_finish(handle);
2394 buffer = srealloc(buffer, buflen+1);
2395 buffer[buflen] = '\0';
2398 nsessions = 1; /* "Default Settings" counts as one */
2400 if (strcmp(p, "Default Settings"))
2406 sessions = smalloc(nsessions * sizeof(char *));
2407 sessions[0] = "Default Settings";
2411 if (strcmp(p, "Default Settings"))
2422 int do_config (void) {
2426 savedsession[0] = '\0';
2427 ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_MAINBOX), NULL, MainDlgProc);
2428 get_sesslist(FALSE);
2433 int do_reconfig (HWND hwnd) {
2437 backup_cfg = cfg; /* structure copy */
2438 ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_RECONF), hwnd, ReconfDlgProc);
2440 cfg = backup_cfg; /* structure copy */
2447 void do_defaults (char *session) {
2449 load_settings (session, TRUE);
2451 load_settings ("Default Settings", FALSE);
2454 void logevent (char *string) {
2455 if (nevents >= negsize) {
2457 events = srealloc (events, negsize * sizeof(*events));
2459 events[nevents] = smalloc(1+strlen(string));
2460 strcpy (events[nevents], string);
2464 SendDlgItemMessage (logbox, IDN_LIST, LB_ADDSTRING,
2466 count = SendDlgItemMessage (logbox, IDN_LIST, LB_GETCOUNT, 0, 0);
2467 SendDlgItemMessage (logbox, IDN_LIST, LB_SETTOPINDEX, count-1, 0);
2471 void showeventlog (HWND hwnd) {
2473 logbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_LOGBOX),
2475 ShowWindow (logbox, SW_SHOWNORMAL);
2479 void showabout (HWND hwnd) {
2481 abtbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
2483 ShowWindow (abtbox, SW_SHOWNORMAL);
2487 void verify_ssh_host_key(char *host, int port, char *keytype,
2488 char *keystr, char *fingerprint) {
2491 static const char absentmsg[] =
2492 "The server's host key is not cached in the registry. You\n"
2493 "have no guarantee that the server is the computer you\n"
2495 "The server's key fingerprint is:\n"
2497 "If you trust this host, hit Yes to add the key to\n"
2498 "PuTTY's cache and carry on connecting.\n"
2499 "If you do not trust this host, hit No to abandon the\n"
2502 static const char wrongmsg[] =
2503 "WARNING - POTENTIAL SECURITY BREACH!\n"
2505 "The server's host key does not match the one PuTTY has\n"
2506 "cached in the registry. This means that either the\n"
2507 "server administrator has changed the host key, or you\n"
2508 "have actually connected to another computer pretending\n"
2509 "to be the server.\n"
2510 "The new key fingerprint is:\n"
2512 "If you were expecting this change and trust the new key,\n"
2513 "hit Yes to update PuTTY's cache and continue connecting.\n"
2514 "If you want to carry on connecting but without updating\n"
2515 "the cache, hit No.\n"
2516 "If you want to abandon the connection completely, hit\n"
2517 "Cancel. Hitting Cancel is the ONLY guaranteed safe\n"
2520 static const char mbtitle[] = "PuTTY Security Alert";
2523 char message[160+ /* sensible fingerprint max size */
2524 (sizeof(absentmsg) > sizeof(wrongmsg) ?
2525 sizeof(absentmsg) : sizeof(wrongmsg))];
2528 * Verify the key against the registry.
2530 ret = verify_host_key(host, port, keytype, keystr);
2532 if (ret == 0) /* success - key matched OK */
2534 if (ret == 2) { /* key was different */
2536 sprintf(message, wrongmsg, fingerprint);
2537 mbret = MessageBox(NULL, message, mbtitle,
2538 MB_ICONWARNING | MB_YESNOCANCEL);
2540 store_host_key(host, port, keytype, keystr);
2541 if (mbret == IDCANCEL)
2544 if (ret == 1) { /* key was absent */
2546 sprintf(message, absentmsg, fingerprint);
2547 mbret = MessageBox(NULL, message, mbtitle,
2548 MB_ICONWARNING | MB_YESNO);
2551 store_host_key(host, port, keytype, keystr);