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 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 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 void doctl(struct ctlpos *cp, RECT r, char *wclass, int wstyle, int exstyle,
486 char *wtext, int wid) {
489 * Note nonstandard use of RECT. This is deliberate: by
490 * transforming the width and height directly we arrange to
491 * have all supposedly same-sized controls really same-sized.
494 /* MapDialogRect, or its near equivalent. */
495 r.left = (r.left * (cp->units & 0xFFFF)) / 4;
496 r.right = (r.right * (cp->units & 0xFFFF)) / 4;
497 r.top = (r.top * ((cp->units>>16) & 0xFFFF)) / 8;
498 r.bottom = (r.bottom * ((cp->units>>16) & 0xFFFF)) / 8;
500 ctl = CreateWindowEx(exstyle, wclass, wtext, wstyle,
501 r.left, r.top, r.right, r.bottom,
502 cp->hwnd, (HMENU)wid, hinst, NULL);
503 SendMessage(ctl, WM_SETFONT, cp->font, MAKELPARAM(TRUE, 0));
507 * Some edit boxes. Each one has a static above it. The percentages
508 * of the horizontal space are provided.
510 void multiedit(struct ctlpos *cp, ...) {
519 int staticid, editid, pcwidth;
520 text = va_arg(ap, char *);
523 staticid = va_arg(ap, int);
524 editid = va_arg(ap, int);
525 pcwidth = va_arg(ap, int);
527 r.left = xpos + GAPBETWEEN;
529 xpos = (cp->width + GAPBETWEEN) * percent / 100;
530 r.right = xpos - r.left;
532 r.top = cp->ypos; r.bottom = STATICHEIGHT;
533 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0,
535 r.top = cp->ypos + 8 + GAPWITHIN; r.bottom = EDITHEIGHT;
537 WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
542 cp->ypos += 8+GAPWITHIN+12+GAPBETWEEN;
546 * A set of radio buttons on the same line, with a static above
547 * them. `nacross' dictates how many parts the line is divided into
548 * (you might want this not to equal the number of buttons if you
549 * needed to line up some 2s and some 3s to look good in the same
552 void radioline(struct ctlpos *cp, char *text, int id, int nacross, ...) {
558 r.left = GAPBETWEEN; r.top = cp->ypos;
559 r.right = cp->width; r.bottom = STATICHEIGHT;
560 cp->ypos += r.bottom + GAPWITHIN;
561 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, text, id);
562 va_start(ap, nacross);
568 btext = va_arg(ap, char *);
571 bid = va_arg(ap, int);
572 r.left = GAPBETWEEN + i * (cp->width+GAPBETWEEN)/nacross;
573 r.right = (i+1) * (cp->width+GAPBETWEEN)/nacross - r.left;
574 r.top = cp->ypos; r.bottom = RADIOHEIGHT;
575 doctl(cp, r, "BUTTON",
576 BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP | group,
583 cp->ypos += r.bottom + GAPBETWEEN;
587 * A set of radio buttons on multiple lines, with a static above
590 void radiobig(struct ctlpos *cp, char *text, int id, ...) {
595 r.left = GAPBETWEEN; r.top = cp->ypos;
596 r.right = cp->width; r.bottom = STATICHEIGHT;
597 cp->ypos += r.bottom + GAPWITHIN;
598 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, text, id);
604 btext = va_arg(ap, char *);
607 bid = va_arg(ap, int);
608 r.left = GAPBETWEEN; r.top = cp->ypos;
609 r.right = cp->width; r.bottom = STATICHEIGHT;
610 cp->ypos += r.bottom + GAPWITHIN;
611 doctl(cp, r, "BUTTON",
612 BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP | group,
618 cp->ypos += GAPBETWEEN - GAPWITHIN;
622 * A single standalone checkbox.
624 void checkbox(struct ctlpos *cp, char *text, int id) {
627 r.left = GAPBETWEEN; r.top = cp->ypos;
628 r.right = cp->width; r.bottom = CHECKBOXHEIGHT;
629 cp->ypos += r.bottom + GAPBETWEEN;
630 doctl(cp, r, "BUTTON",
631 BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0,
636 * A button on the right hand side, with a static to its left.
638 void staticbtn(struct ctlpos *cp, char *stext, int sid, char *btext, int bid) {
639 const int height = (PUSHBTNHEIGHT > STATICHEIGHT ?
640 PUSHBTNHEIGHT : STATICHEIGHT);
642 int lwid, rwid, rpos;
644 rpos = GAPBETWEEN + 3 * (cp->width + GAPBETWEEN) / 4;
645 lwid = rpos - 2*GAPBETWEEN;
646 rwid = cp->width + GAPBETWEEN - rpos;
648 r.left = GAPBETWEEN; r.top = cp->ypos + (height-STATICHEIGHT)/2;
649 r.right = lwid; r.bottom = STATICHEIGHT;
650 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
652 r.left = rpos; r.top = cp->ypos + (height-PUSHBTNHEIGHT)/2;
653 r.right = rwid; r.bottom = PUSHBTNHEIGHT;
654 doctl(cp, r, "BUTTON",
655 WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
659 cp->ypos += height + GAPBETWEEN;
663 * An edit control on the right hand side, with a static to its left.
665 void staticedit(struct ctlpos *cp, char *stext, int sid, int eid) {
666 const int height = (EDITHEIGHT > STATICHEIGHT ?
667 EDITHEIGHT : STATICHEIGHT);
669 int lwid, rwid, rpos;
671 rpos = GAPBETWEEN + (cp->width + GAPBETWEEN) / 2;
672 lwid = rpos - 2*GAPBETWEEN;
673 rwid = cp->width + GAPBETWEEN - rpos;
675 r.left = GAPBETWEEN; r.top = cp->ypos + (height-STATICHEIGHT)/2;
676 r.right = lwid; r.bottom = STATICHEIGHT;
677 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
679 r.left = rpos; r.top = cp->ypos + (height-EDITHEIGHT)/2;
680 r.right = rwid; r.bottom = EDITHEIGHT;
682 WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
686 cp->ypos += height + GAPBETWEEN;
690 * A tab-control substitute when a real tab control is unavailable.
692 void ersatztab(struct ctlpos *cp, char *stext, int sid, int lid, int s2id) {
693 const int height = (COMBOHEIGHT > STATICHEIGHT ?
694 COMBOHEIGHT : STATICHEIGHT);
696 int bigwid, lwid, rwid, rpos;
697 static const int BIGGAP = 15;
698 static const int MEDGAP = 3;
700 bigwid = cp->width + 2*GAPBETWEEN - 2*BIGGAP;
702 rpos = BIGGAP + (bigwid + BIGGAP) / 2;
703 lwid = rpos - 2*BIGGAP;
704 rwid = bigwid + BIGGAP - rpos;
706 r.left = BIGGAP; r.top = cp->ypos + (height-STATICHEIGHT)/2;
707 r.right = lwid; r.bottom = STATICHEIGHT;
708 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
710 r.left = rpos; r.top = cp->ypos + (height-COMBOHEIGHT)/2;
711 r.right = rwid; r.bottom = COMBOHEIGHT*10;
712 doctl(cp, r, "COMBOBOX",
713 WS_CHILD | WS_VISIBLE | WS_TABSTOP |
714 CBS_DROPDOWNLIST | CBS_HASSTRINGS,
718 cp->ypos += height + MEDGAP + GAPBETWEEN;
720 r.left = GAPBETWEEN; r.top = cp->ypos;
721 r.right = cp->width; r.bottom = 2;
722 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE | SS_ETCHEDHORZ,
727 * A static line, followed by an edit control on the left hand side
728 * and a button on the right.
730 void editbutton(struct ctlpos *cp, char *stext, int sid,
731 int eid, char *btext, int bid) {
732 const int height = (EDITHEIGHT > PUSHBTNHEIGHT ?
733 EDITHEIGHT : PUSHBTNHEIGHT);
735 int lwid, rwid, rpos;
737 r.left = GAPBETWEEN; r.top = cp->ypos;
738 r.right = cp->width; r.bottom = STATICHEIGHT;
739 cp->ypos += r.bottom + GAPWITHIN;
740 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
742 rpos = GAPBETWEEN + 3 * (cp->width + GAPBETWEEN) / 4;
743 lwid = rpos - 2*GAPBETWEEN;
744 rwid = cp->width + GAPBETWEEN - rpos;
746 r.left = GAPBETWEEN; r.top = cp->ypos + (height-EDITHEIGHT)/2;
747 r.right = lwid; r.bottom = EDITHEIGHT;
749 WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
753 r.left = rpos; r.top = cp->ypos + (height-PUSHBTNHEIGHT)/2;
754 r.right = rwid; r.bottom = PUSHBTNHEIGHT;
755 doctl(cp, r, "BUTTON",
756 WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
760 cp->ypos += height + GAPBETWEEN;
764 * Special control which was hard to describe generically: the
765 * session-saver assembly. A static; below that an edit box; below
766 * that a list box. To the right of the list box, a column of
769 void sesssaver(struct ctlpos *cp, char *text,
770 int staticid, int editid, int listid, ...) {
773 int lwid, rwid, rpos;
775 const int LISTDEFHEIGHT = 66;
777 rpos = GAPBETWEEN + 3 * (cp->width + GAPBETWEEN) / 4;
778 lwid = rpos - 2*GAPBETWEEN;
779 rwid = cp->width + GAPBETWEEN - rpos;
781 /* The static control. */
782 r.left = GAPBETWEEN; r.top = cp->ypos;
783 r.right = lwid; r.bottom = STATICHEIGHT;
784 cp->ypos += r.bottom + GAPWITHIN;
785 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, text, staticid);
787 /* The edit control. */
788 r.left = GAPBETWEEN; r.top = cp->ypos;
789 r.right = lwid; r.bottom = EDITHEIGHT;
790 cp->ypos += r.bottom + GAPWITHIN;
792 WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
797 * The buttons (we should hold off on the list box until we
798 * know how big the buttons are).
800 va_start(ap, listid);
803 char *btext = va_arg(ap, char *);
806 bid = va_arg(ap, int);
807 r.left = rpos; r.top = y;
808 r.right = rwid; r.bottom = PUSHBTNHEIGHT;
809 y += r.bottom + GAPWITHIN;
810 doctl(cp, r, "BUTTON",
811 WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
816 /* Compute list box height. LISTDEFHEIGHT, or height of buttons. */
819 if (y < LISTDEFHEIGHT) y = LISTDEFHEIGHT;
820 r.left = GAPBETWEEN; r.top = cp->ypos;
821 r.right = lwid; r.bottom = y;
822 cp->ypos += y + GAPBETWEEN;
823 doctl(cp, r, "LISTBOX",
824 WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL |
825 LBS_STANDARD | LBS_HASSTRINGS,
831 * Another special control: the environment-variable setter. A
832 * static line first; then a pair of edit boxes with associated
833 * statics, and two buttons; then a list box.
835 void envsetter(struct ctlpos *cp, char *stext, int sid,
836 char *e1stext, int e1sid, int e1id,
837 char *e2stext, int e2sid, int e2id,
838 int listid, char *b1text, int b1id, char *b2text, int b2id) {
840 const int height = (STATICHEIGHT > EDITHEIGHT && STATICHEIGHT > PUSHBTNHEIGHT ?
842 EDITHEIGHT > PUSHBTNHEIGHT ?
843 EDITHEIGHT : PUSHBTNHEIGHT);
844 const static int percents[] = { 20, 35, 10, 25 };
845 int i, j, xpos, percent;
846 const int LISTHEIGHT = 42;
848 /* The static control. */
849 r.left = GAPBETWEEN; r.top = cp->ypos;
850 r.right = cp->width; r.bottom = STATICHEIGHT;
851 cp->ypos += r.bottom + GAPWITHIN;
852 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
854 /* The statics+edits+buttons. */
855 for (j = 0; j < 2; j++) {
857 for (i = 0; i < 4; i++) {
858 xpos = (cp->width + GAPBETWEEN) * percent / 100;
859 r.left = xpos + GAPBETWEEN;
860 percent += percents[i];
861 xpos = (cp->width + GAPBETWEEN) * percent / 100;
862 r.right = xpos - r.left;
864 r.bottom = (i==0 ? STATICHEIGHT :
867 r.top += (height-r.bottom)/2;
869 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0,
870 j==0 ? e1stext : e2stext, j==0 ? e1sid : e2sid);
873 WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
875 "", j==0 ? e1id : e2id);
877 doctl(cp, r, "BUTTON",
878 WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
880 j==0 ? b1text : b2text, j==0 ? b1id : b2id);
883 cp->ypos += height + GAPWITHIN;
887 r.left = GAPBETWEEN; r.top = cp->ypos;
888 r.right = cp->width; r.bottom = LISTHEIGHT;
889 cp->ypos += r.bottom + GAPBETWEEN;
890 doctl(cp, r, "LISTBOX",
891 WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL | LBS_HASSTRINGS |
898 * Yet another special control: the character-class setter. A
899 * static, then a list, then a line containing a
900 * button-and-static-and-edit.
902 void charclass(struct ctlpos *cp, char *stext, int sid, int listid,
903 char *btext, int bid, int eid, char *s2text, int s2id) {
905 const int height = (STATICHEIGHT > EDITHEIGHT && STATICHEIGHT > PUSHBTNHEIGHT ?
907 EDITHEIGHT > PUSHBTNHEIGHT ?
908 EDITHEIGHT : PUSHBTNHEIGHT);
909 const static int percents[] = { 30, 40, 30 };
910 int i, xpos, percent;
911 const int LISTHEIGHT = 66;
913 /* The static control. */
914 r.left = GAPBETWEEN; r.top = cp->ypos;
915 r.right = cp->width; r.bottom = STATICHEIGHT;
916 cp->ypos += r.bottom + GAPWITHIN;
917 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
920 r.left = GAPBETWEEN; r.top = cp->ypos;
921 r.right = cp->width; r.bottom = LISTHEIGHT;
922 cp->ypos += r.bottom + GAPWITHIN;
923 doctl(cp, r, "LISTBOX",
924 WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL | LBS_HASSTRINGS |
929 /* The button+static+edit. */
931 for (i = 0; i < 3; i++) {
932 r.left = xpos + GAPBETWEEN;
933 percent += percents[i];
934 xpos = (cp->width + GAPBETWEEN) * percent / 100;
935 r.right = xpos - r.left;
937 r.bottom = (i==0 ? PUSHBTNHEIGHT :
938 i==1 ? STATICHEIGHT :
940 r.top += (height-r.bottom)/2;
942 doctl(cp, r, "BUTTON",
943 WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
946 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE | SS_CENTER,
950 WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
951 WS_EX_CLIENTEDGE, "", eid);
954 cp->ypos += height + GAPBETWEEN;
958 * A special control (horrors!). The colour editor. A static line;
959 * then on the left, a list box, and on the right, a sequence of
960 * two-part statics followed by a button.
962 void colouredit(struct ctlpos *cp, char *stext, int sid, int listid,
963 char *btext, int bid, ...) {
967 int lwid, rwid, rpos;
968 const int LISTHEIGHT = 66;
970 /* The static control. */
971 r.left = GAPBETWEEN; r.top = cp->ypos;
972 r.right = cp->width; r.bottom = STATICHEIGHT;
973 cp->ypos += r.bottom + GAPWITHIN;
974 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
976 rpos = GAPBETWEEN + 2 * (cp->width + GAPBETWEEN) / 3;
977 lwid = rpos - 2*GAPBETWEEN;
978 rwid = cp->width + GAPBETWEEN - rpos;
981 r.left = GAPBETWEEN; r.top = cp->ypos;
982 r.right = lwid; r.bottom = LISTHEIGHT;
983 doctl(cp, r, "LISTBOX",
984 WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL | LBS_HASSTRINGS |
995 ltext = va_arg(ap, char *);
997 lid = va_arg(ap, int);
998 rid = va_arg(ap, int);
999 r.top = y; r.bottom = STATICHEIGHT;
1000 y += r.bottom + GAPWITHIN;
1001 r.left = rpos; r.right = rwid/2;
1002 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, ltext, lid);
1003 r.left = rpos + r.right; r.right = rwid - r.right;
1004 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE | SS_RIGHT, 0, "", rid);
1009 r.top = y + 2*GAPWITHIN; r.bottom = PUSHBTNHEIGHT;
1010 r.left = rpos; r.right = rwid;
1011 doctl(cp, r, "BUTTON",
1012 WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
1015 cp->ypos += LISTHEIGHT + GAPBETWEEN;
1018 static int GeneralPanelProc (HWND hwnd, UINT msg,
1019 WPARAM wParam, LPARAM lParam) {
1023 HFONT hfont = (HFONT)wParam;
1030 oldfont = SelectObject(hdc, hfont);
1031 GetTextMetrics(hdc, &tm);
1032 units = (tm.tmHeight << 16) | tm.tmAveCharWidth;
1033 SelectObject(hdc, oldfont);
1035 SetWindowLong(hwnd, GWL_USERDATA, units);
1036 SetWindowLong(hwnd, DWL_USER, wParam);
1040 SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
1043 DestroyWindow (hwnd);
1049 static char savedsession[2048];
1051 static int CALLBACK ConnectionProc (HWND hwnd, UINT msg,
1052 WPARAM wParam, LPARAM lParam) {
1058 /* Accelerators used: [aco] dehlnprstwx */
1059 ctlposinit(&cp, hwnd);
1061 "Host &Name", IDC0_HOSTSTATIC, IDC0_HOST, 75,
1062 "&Port", IDC0_PORTSTATIC, IDC0_PORT, 25, NULL);
1063 radioline(&cp, "Protocol:", IDC0_PROTSTATIC, 3,
1064 "&Raw", IDC0_PROTRAW,
1065 "&Telnet", IDC0_PROTTELNET,
1071 IDC0_PROTSSH, NULL);
1072 sesssaver(&cp, "Stor&ed Sessions",
1073 IDC0_SESSSTATIC, IDC0_SESSEDIT, IDC0_SESSLIST,
1074 "&Load", IDC0_SESSLOAD,
1075 "&Save", IDC0_SESSSAVE,
1076 "&Delete", IDC0_SESSDEL, NULL);
1077 checkbox(&cp, "Close Window on E&xit", IDC0_CLOSEEXIT);
1078 checkbox(&cp, "&Warn on Close", IDC0_CLOSEWARN);
1080 SetDlgItemText (hwnd, IDC0_HOST, cfg.host);
1081 SetDlgItemText (hwnd, IDC0_SESSEDIT, savedsession);
1082 SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE);
1083 for (i = 0; i < nsessions; i++)
1084 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING,
1085 0, (LPARAM) (sessions[i]));
1086 CheckRadioButton (hwnd, IDC0_PROTRAW, IDC0_PROTSSH,
1087 cfg.protocol==PROT_SSH ? IDC0_PROTSSH :
1088 cfg.protocol==PROT_TELNET ? IDC0_PROTTELNET : IDC0_PROTRAW );
1089 CheckDlgButton (hwnd, IDC0_CLOSEEXIT, cfg.close_on_exit);
1090 CheckDlgButton (hwnd, IDC0_CLOSEWARN, cfg.warn_on_close);
1094 * Button release should trigger WM_OK if there was a
1095 * previous double click on the session list.
1099 SendMessage (GetParent(hwnd), WM_COMMAND, IDOK, 0);
1102 switch (LOWORD(wParam)) {
1103 case IDC0_PROTTELNET:
1106 if (HIWORD(wParam) == BN_CLICKED ||
1107 HIWORD(wParam) == BN_DOUBLECLICKED) {
1108 int i = IsDlgButtonChecked (hwnd, IDC0_PROTSSH);
1109 int j = IsDlgButtonChecked (hwnd, IDC0_PROTTELNET);
1110 cfg.protocol = i ? PROT_SSH : j ? PROT_TELNET : PROT_RAW ;
1111 if ((cfg.protocol == PROT_SSH && cfg.port == 23) ||
1112 (cfg.protocol == PROT_TELNET && cfg.port == 22)) {
1113 cfg.port = i ? 22 : 23;
1114 SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE);
1119 if (HIWORD(wParam) == EN_CHANGE)
1120 GetDlgItemText (hwnd, IDC0_HOST, cfg.host,
1121 sizeof(cfg.host)-1);
1124 if (HIWORD(wParam) == EN_CHANGE)
1125 MyGetDlgItemInt (hwnd, IDC0_PORT, &cfg.port);
1127 case IDC0_CLOSEEXIT:
1128 if (HIWORD(wParam) == BN_CLICKED ||
1129 HIWORD(wParam) == BN_DOUBLECLICKED)
1130 cfg.close_on_exit = IsDlgButtonChecked (hwnd, IDC0_CLOSEEXIT);
1132 case IDC0_CLOSEWARN:
1133 if (HIWORD(wParam) == BN_CLICKED ||
1134 HIWORD(wParam) == BN_DOUBLECLICKED)
1135 cfg.warn_on_close = IsDlgButtonChecked (hwnd, IDC0_CLOSEWARN);
1138 if (HIWORD(wParam) == EN_CHANGE) {
1139 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
1141 GetDlgItemText (hwnd, IDC0_SESSEDIT,
1142 savedsession, sizeof(savedsession)-1);
1143 savedsession[sizeof(savedsession)-1] = '\0';
1147 if (HIWORD(wParam) == BN_CLICKED ||
1148 HIWORD(wParam) == BN_DOUBLECLICKED) {
1153 GetDlgItemText (hwnd, IDC0_SESSEDIT, str, sizeof(str)-1);
1155 int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
1156 LB_GETCURSEL, 0, 0);
1161 strcpy (str, sessions[n]);
1163 save_settings (str, !!strcmp(str, "Default Settings"));
1164 get_sesslist (FALSE);
1165 get_sesslist (TRUE);
1166 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_RESETCONTENT,
1168 for (i = 0; i < nsessions; i++)
1169 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING,
1170 0, (LPARAM) (sessions[i]));
1171 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
1177 if (LOWORD(wParam) == IDC0_SESSLOAD &&
1178 HIWORD(wParam) != BN_CLICKED &&
1179 HIWORD(wParam) != BN_DOUBLECLICKED)
1181 if (LOWORD(wParam) == IDC0_SESSLIST &&
1182 HIWORD(wParam) != LBN_DBLCLK)
1185 int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
1186 LB_GETCURSEL, 0, 0);
1191 load_settings (sessions[n],
1192 !!strcmp(sessions[n], "Default Settings"));
1193 SetDlgItemText (hwnd, IDC0_HOST, cfg.host);
1194 SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE);
1195 CheckRadioButton (hwnd, IDC0_PROTRAW, IDC0_PROTSSH,
1196 (cfg.protocol==PROT_SSH ? IDC0_PROTSSH :
1197 cfg.protocol==PROT_TELNET ? IDC0_PROTTELNET : IDC0_PROTRAW));
1198 CheckDlgButton (hwnd, IDC0_CLOSEEXIT, cfg.close_on_exit);
1199 CheckDlgButton (hwnd, IDC0_CLOSEWARN, cfg.warn_on_close);
1200 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
1203 if (LOWORD(wParam) == IDC0_SESSLIST) {
1205 * A double-click on a saved session should
1206 * actually start the session, not just load it.
1207 * Unless it's Default Settings or some other
1208 * host-less set of saved settings.
1217 if (HIWORD(wParam) == BN_CLICKED ||
1218 HIWORD(wParam) == BN_DOUBLECLICKED) {
1219 int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
1220 LB_GETCURSEL, 0, 0);
1221 if (n == LB_ERR || n == 0) {
1225 del_settings(sessions[n]);
1226 get_sesslist (FALSE);
1227 get_sesslist (TRUE);
1228 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_RESETCONTENT,
1230 for (i = 0; i < nsessions; i++)
1231 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING,
1232 0, (LPARAM) (sessions[i]));
1233 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
1238 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1241 static int CALLBACK KeyboardProc (HWND hwnd, UINT msg,
1242 WPARAM wParam, LPARAM lParam) {
1246 /* Accelerators used: [aco] 4?ehiklmnprsuvxy */
1247 ctlposinit(&cp, hwnd);
1248 radioline(&cp, "Action of Backspace:", IDC1_DELSTATIC, 2,
1249 "Control-&H", IDC1_DEL008,
1250 "Control-&? (127)", IDC1_DEL127, NULL);
1251 radioline(&cp, "Action of Home and End:", IDC1_HOMESTATIC, 2,
1252 "&Standard", IDC1_HOMETILDE,
1253 "&rxvt", IDC1_HOMERXVT, NULL);
1254 radioline(&cp, "Function key and keypad layout:", IDC1_FUNCSTATIC, 3,
1255 "&VT400", IDC1_FUNCTILDE,
1256 "&Linux", IDC1_FUNCLINUX,
1257 "&Xterm R6", IDC1_FUNCXTERM, NULL);
1258 radioline(&cp, "Initial state of cursor keys:", IDC1_CURSTATIC, 2,
1259 "&Normal", IDC1_CURNORMAL,
1260 "A&pplication", IDC1_CURAPPLIC, NULL);
1261 radioline(&cp, "Initial state of numeric keypad:", IDC1_KPSTATIC, 3,
1262 "Nor&mal", IDC1_KPNORMAL,
1263 "Appl&ication", IDC1_KPAPPLIC,
1264 "N&etHack", IDC1_KPNH, NULL);
1265 checkbox(&cp, "ALT-F&4 is special (closes window)", IDC1_ALTF4);
1266 checkbox(&cp, "ALT-Space is special (S&ystem menu)", IDC1_ALTSPACE);
1267 checkbox(&cp, "&Use local terminal line discipline", IDC1_LDISCTERM);
1268 checkbox(&cp, "Reset scrollback on &keypress", IDC1_SCROLLKEY);
1270 CheckRadioButton (hwnd, IDC1_DEL008, IDC1_DEL127,
1271 cfg.bksp_is_delete ? IDC1_DEL127 : IDC1_DEL008);
1272 CheckRadioButton (hwnd, IDC1_HOMETILDE, IDC1_HOMERXVT,
1273 cfg.rxvt_homeend ? IDC1_HOMERXVT : IDC1_HOMETILDE);
1274 CheckRadioButton (hwnd, IDC1_FUNCTILDE, IDC1_FUNCXTERM,
1276 (cfg.funky_type==2 ? IDC1_FUNCXTERM
1279 CheckRadioButton (hwnd, IDC1_CURNORMAL, IDC1_CURAPPLIC,
1280 cfg.app_cursor ? IDC1_CURAPPLIC : IDC1_CURNORMAL);
1281 CheckRadioButton (hwnd, IDC1_KPNORMAL, IDC1_KPNH,
1282 cfg.nethack_keypad ? IDC1_KPNH :
1283 cfg.app_keypad ? IDC1_KPAPPLIC : IDC1_KPNORMAL);
1284 CheckDlgButton (hwnd, IDC1_ALTF4, cfg.alt_f4);
1285 CheckDlgButton (hwnd, IDC1_ALTSPACE, cfg.alt_space);
1286 CheckDlgButton (hwnd, IDC1_LDISCTERM, cfg.ldisc_term);
1287 CheckDlgButton (hwnd, IDC1_SCROLLKEY, cfg.scroll_on_key);
1290 if (HIWORD(wParam) == BN_CLICKED ||
1291 HIWORD(wParam) == BN_DOUBLECLICKED)
1292 switch (LOWORD(wParam)) {
1295 cfg.bksp_is_delete = IsDlgButtonChecked (hwnd, IDC1_DEL127);
1297 case IDC1_HOMETILDE:
1299 cfg.rxvt_homeend = IsDlgButtonChecked (hwnd, IDC1_HOMERXVT);
1301 case IDC1_FUNCXTERM:
1304 case IDC1_FUNCTILDE:
1305 case IDC1_FUNCLINUX:
1306 cfg.funky_type = IsDlgButtonChecked (hwnd, IDC1_FUNCLINUX);
1310 cfg.app_keypad = IsDlgButtonChecked (hwnd, IDC1_KPAPPLIC);
1311 cfg.nethack_keypad = FALSE;
1314 cfg.app_keypad = FALSE;
1315 cfg.nethack_keypad = TRUE;
1317 case IDC1_CURNORMAL:
1318 case IDC1_CURAPPLIC:
1319 cfg.app_cursor = IsDlgButtonChecked (hwnd, IDC1_CURAPPLIC);
1322 if (HIWORD(wParam) == BN_CLICKED ||
1323 HIWORD(wParam) == BN_DOUBLECLICKED)
1324 cfg.alt_f4 = IsDlgButtonChecked (hwnd, IDC1_ALTF4);
1327 if (HIWORD(wParam) == BN_CLICKED ||
1328 HIWORD(wParam) == BN_DOUBLECLICKED)
1329 cfg.alt_space = IsDlgButtonChecked (hwnd, IDC1_ALTSPACE);
1331 case IDC1_LDISCTERM:
1332 if (HIWORD(wParam) == BN_CLICKED ||
1333 HIWORD(wParam) == BN_DOUBLECLICKED)
1334 cfg.ldisc_term = IsDlgButtonChecked (hwnd, IDC1_LDISCTERM);
1336 case IDC1_SCROLLKEY:
1337 if (HIWORD(wParam) == BN_CLICKED ||
1338 HIWORD(wParam) == BN_DOUBLECLICKED)
1339 cfg.scroll_on_key = IsDlgButtonChecked (hwnd, IDC1_SCROLLKEY);
1343 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1346 static void fmtfont (char *buf) {
1347 sprintf (buf, "Font: %s, ", cfg.font);
1349 strcat(buf, "bold, ");
1350 if (cfg.fontheight == 0)
1351 strcat (buf, "default height");
1353 sprintf (buf+strlen(buf), "%d-%s",
1354 (cfg.fontheight < 0 ? -cfg.fontheight : cfg.fontheight),
1355 (cfg.fontheight < 0 ? "pixel" : "point"));
1358 static int CALLBACK TerminalProc (HWND hwnd, UINT msg,
1359 WPARAM wParam, LPARAM lParam) {
1363 char fontstatic[256];
1367 /* Accelerators used: [aco] dghlmnprsw */
1368 ctlposinit(&cp, hwnd);
1370 "&Rows", IDC2_ROWSSTATIC, IDC2_ROWSEDIT, 33,
1371 "Colu&mns", IDC2_COLSSTATIC, IDC2_COLSEDIT, 33,
1372 "&Scrollback", IDC2_SAVESTATIC, IDC2_SAVEEDIT, 33,
1374 staticbtn(&cp, "", IDC2_FONTSTATIC, "C&hange...", IDC2_CHOOSEFONT);
1375 checkbox(&cp, "Auto &wrap mode initially on", IDC2_WRAPMODE);
1376 checkbox(&cp, "&DEC Origin Mode initially on", IDC2_DECOM);
1377 checkbox(&cp, "Implicit CR in every &LF", IDC2_LFHASCR);
1378 checkbox(&cp, "Bee&p enabled", IDC1_BEEP);
1379 checkbox(&cp, "Use Back&ground colour erase", IDC2_BCE);
1380 checkbox(&cp, "Enable bli&nking text", IDC2_BLINKTEXT);
1382 CheckDlgButton (hwnd, IDC2_WRAPMODE, cfg.wrap_mode);
1383 CheckDlgButton (hwnd, IDC2_DECOM, cfg.dec_om);
1384 CheckDlgButton (hwnd, IDC2_LFHASCR, cfg.lfhascr);
1385 SetDlgItemInt (hwnd, IDC2_ROWSEDIT, cfg.height, FALSE);
1386 SetDlgItemInt (hwnd, IDC2_COLSEDIT, cfg.width, FALSE);
1387 SetDlgItemInt (hwnd, IDC2_SAVEEDIT, cfg.savelines, FALSE);
1388 fmtfont (fontstatic);
1389 SetDlgItemText (hwnd, IDC2_FONTSTATIC, fontstatic);
1390 CheckDlgButton (hwnd, IDC1_BEEP, cfg.beep);
1391 CheckDlgButton (hwnd, IDC2_BCE, cfg.bce);
1392 CheckDlgButton (hwnd, IDC2_BLINKTEXT, cfg.blinktext);
1395 switch (LOWORD(wParam)) {
1397 if (HIWORD(wParam) == BN_CLICKED ||
1398 HIWORD(wParam) == BN_DOUBLECLICKED)
1399 cfg.wrap_mode = IsDlgButtonChecked (hwnd, IDC2_WRAPMODE);
1402 if (HIWORD(wParam) == BN_CLICKED ||
1403 HIWORD(wParam) == BN_DOUBLECLICKED)
1404 cfg.dec_om = IsDlgButtonChecked (hwnd, IDC2_DECOM);
1407 if (HIWORD(wParam) == BN_CLICKED ||
1408 HIWORD(wParam) == BN_DOUBLECLICKED)
1409 cfg.lfhascr = IsDlgButtonChecked (hwnd, IDC2_LFHASCR);
1412 if (HIWORD(wParam) == EN_CHANGE)
1413 MyGetDlgItemInt (hwnd, IDC2_ROWSEDIT, &cfg.height);
1416 if (HIWORD(wParam) == EN_CHANGE)
1417 MyGetDlgItemInt (hwnd, IDC2_COLSEDIT, &cfg.width);
1420 if (HIWORD(wParam) == EN_CHANGE)
1421 MyGetDlgItemInt (hwnd, IDC2_SAVEEDIT, &cfg.savelines);
1423 case IDC2_CHOOSEFONT:
1424 lf.lfHeight = cfg.fontheight;
1425 lf.lfWidth = lf.lfEscapement = lf.lfOrientation = 0;
1426 lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = 0;
1427 lf.lfWeight = (cfg.fontisbold ? FW_BOLD : 0);
1428 lf.lfCharSet = cfg.fontcharset;
1429 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
1430 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1431 lf.lfQuality = DEFAULT_QUALITY;
1432 lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
1433 strncpy (lf.lfFaceName, cfg.font, sizeof(lf.lfFaceName)-1);
1434 lf.lfFaceName[sizeof(lf.lfFaceName)-1] = '\0';
1436 cf.lStructSize = sizeof(cf);
1437 cf.hwndOwner = hwnd;
1439 cf.Flags = CF_FIXEDPITCHONLY | CF_FORCEFONTEXIST |
1440 CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
1442 if (ChooseFont (&cf)) {
1443 strncpy (cfg.font, lf.lfFaceName, sizeof(cfg.font)-1);
1444 cfg.font[sizeof(cfg.font)-1] = '\0';
1445 cfg.fontisbold = (lf.lfWeight == FW_BOLD);
1446 cfg.fontcharset = lf.lfCharSet;
1447 cfg.fontheight = lf.lfHeight;
1448 fmtfont (fontstatic);
1449 SetDlgItemText (hwnd, IDC2_FONTSTATIC, fontstatic);
1453 if (HIWORD(wParam) == BN_CLICKED ||
1454 HIWORD(wParam) == BN_DOUBLECLICKED)
1455 cfg.beep = IsDlgButtonChecked (hwnd, IDC1_BEEP);
1457 case IDC2_BLINKTEXT:
1458 if (HIWORD(wParam) == BN_CLICKED ||
1459 HIWORD(wParam) == BN_DOUBLECLICKED)
1460 cfg.blinktext = IsDlgButtonChecked (hwnd, IDC2_BLINKTEXT);
1463 if (HIWORD(wParam) == BN_CLICKED ||
1464 HIWORD(wParam) == BN_DOUBLECLICKED)
1465 cfg.bce = IsDlgButtonChecked (hwnd, IDC2_BCE);
1470 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1473 static int CALLBACK WindowProc (HWND hwnd, UINT msg,
1474 WPARAM wParam, LPARAM lParam) {
1478 /* Accelerators used: [aco] bikty */
1479 ctlposinit(&cp, hwnd);
1481 "Initial window &title:", IDCW_WINTITLE, IDCW_WINEDIT, 100,
1483 checkbox(&cp, "Avoid ever using &icon title", IDCW_WINNAME);
1484 checkbox(&cp, "&Blinking cursor", IDCW_BLINKCUR);
1485 checkbox(&cp, "Displa&y scrollbar", IDCW_SCROLLBAR);
1486 checkbox(&cp, "Loc&k Window size", IDCW_LOCKSIZE);
1488 SetDlgItemText (hwnd, IDCW_WINEDIT, cfg.wintitle);
1489 CheckDlgButton (hwnd, IDCW_WINNAME, cfg.win_name_always);
1490 CheckDlgButton (hwnd, IDCW_BLINKCUR, cfg.blink_cur);
1491 CheckDlgButton (hwnd, IDCW_SCROLLBAR, cfg.scrollbar);
1492 CheckDlgButton (hwnd, IDCW_LOCKSIZE, cfg.locksize);
1495 switch (LOWORD(wParam)) {
1497 if (HIWORD(wParam) == BN_CLICKED ||
1498 HIWORD(wParam) == BN_DOUBLECLICKED)
1499 cfg.win_name_always = IsDlgButtonChecked (hwnd, IDCW_WINNAME);
1502 if (HIWORD(wParam) == BN_CLICKED ||
1503 HIWORD(wParam) == BN_DOUBLECLICKED)
1504 cfg.blink_cur = IsDlgButtonChecked (hwnd, IDCW_BLINKCUR);
1506 case IDCW_SCROLLBAR:
1507 if (HIWORD(wParam) == BN_CLICKED ||
1508 HIWORD(wParam) == BN_DOUBLECLICKED)
1509 cfg.scrollbar = IsDlgButtonChecked (hwnd, IDCW_SCROLLBAR);
1512 if (HIWORD(wParam) == BN_CLICKED ||
1513 HIWORD(wParam) == BN_DOUBLECLICKED)
1514 cfg.locksize = IsDlgButtonChecked (hwnd, IDCW_LOCKSIZE);
1517 if (HIWORD(wParam) == EN_CHANGE)
1518 GetDlgItemText (hwnd, IDCW_WINEDIT, cfg.wintitle,
1519 sizeof(cfg.wintitle)-1);
1524 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1527 static int CALLBACK TelnetProc (HWND hwnd, UINT msg,
1528 WPARAM wParam, LPARAM lParam) {
1534 /* Accelerators used: [aco] bdflrstuv */
1535 ctlposinit(&cp, hwnd);
1536 staticedit(&cp, "Terminal-&type string", IDC3_TTSTATIC, IDC3_TTEDIT);
1537 staticedit(&cp, "Terminal-&speed string", IDC3_TSSTATIC, IDC3_TSEDIT);
1538 staticedit(&cp, "Auto-login &username", IDC3_LOGSTATIC, IDC3_LOGEDIT);
1539 envsetter(&cp, "Environment variables:", IDC3_ENVSTATIC,
1540 "&Variable", IDC3_VARSTATIC, IDC3_VAREDIT,
1541 "Va&lue", IDC3_VALSTATIC, IDC3_VALEDIT,
1543 "A&dd", IDC3_ENVADD, "&Remove", IDC3_ENVREMOVE);
1544 radioline(&cp, "Handling of OLD_ENVIRON ambiguity:", IDC3_EMSTATIC, 2,
1545 "&BSD (commonplace)", IDC3_EMBSD,
1546 "R&FC 1408 (unusual)", IDC3_EMRFC, NULL);
1548 SetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype);
1549 SetDlgItemText (hwnd, IDC3_TSEDIT, cfg.termspeed);
1550 SetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username);
1552 char *p = cfg.environmt;
1554 SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_ADDSTRING, 0,
1559 CheckRadioButton (hwnd, IDC3_EMBSD, IDC3_EMRFC,
1560 cfg.rfc_environ ? IDC3_EMRFC : IDC3_EMBSD);
1563 switch (LOWORD(wParam)) {
1565 if (HIWORD(wParam) == EN_CHANGE)
1566 GetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype,
1567 sizeof(cfg.termtype)-1);
1570 if (HIWORD(wParam) == EN_CHANGE)
1571 GetDlgItemText (hwnd, IDC3_TSEDIT, cfg.termspeed,
1572 sizeof(cfg.termspeed)-1);
1575 if (HIWORD(wParam) == EN_CHANGE)
1576 GetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username,
1577 sizeof(cfg.username)-1);
1581 cfg.rfc_environ = IsDlgButtonChecked (hwnd, IDC3_EMRFC);
1584 if (HIWORD(wParam) == BN_CLICKED ||
1585 HIWORD(wParam) == BN_DOUBLECLICKED) {
1586 char str[sizeof(cfg.environmt)];
1588 GetDlgItemText (hwnd, IDC3_VAREDIT, str, sizeof(str)-1);
1593 p = str + strlen(str);
1595 GetDlgItemText (hwnd, IDC3_VALEDIT, p, sizeof(str)-1-(p-str));
1605 if ((p-cfg.environmt) + strlen(str) + 2 < sizeof(cfg.environmt)) {
1607 p[strlen(str)+1] = '\0';
1608 SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_ADDSTRING,
1610 SetDlgItemText (hwnd, IDC3_VAREDIT, "");
1611 SetDlgItemText (hwnd, IDC3_VALEDIT, "");
1613 MessageBox(hwnd, "Environment too big", "PuTTY Error",
1614 MB_OK | MB_ICONERROR);
1618 case IDC3_ENVREMOVE:
1619 if (HIWORD(wParam) != BN_CLICKED &&
1620 HIWORD(wParam) != BN_DOUBLECLICKED)
1622 i = SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_GETCURSEL, 0, 0);
1628 SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_DELETESTRING,
1655 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1658 static int CALLBACK SshProc (HWND hwnd, UINT msg,
1659 WPARAM wParam, LPARAM lParam) {
1662 char filename[sizeof(cfg.keyfile)];
1666 /* Accelerators used: [aco] 123abdkmprtuw */
1667 ctlposinit(&cp, hwnd);
1668 staticedit(&cp, "Terminal-&type string", IDC3_TTSTATIC, IDC3_TTEDIT);
1669 staticedit(&cp, "Auto-login &username", IDC3_LOGSTATIC, IDC3_LOGEDIT);
1671 "&Remote command:", IDC3_CMDSTATIC, IDC3_CMDEDIT, 100,
1673 checkbox(&cp, "Don't allocate a &pseudo-terminal", IDC3_NOPTY);
1674 checkbox(&cp, "Atte&mpt TIS or CryptoCard authentication",
1676 checkbox(&cp, "Allow &agent forwarding", IDC3_AGENTFWD);
1677 editbutton(&cp, "Private &key file for authentication:",
1678 IDC3_PKSTATIC, IDC3_PKEDIT, "Bro&wse...", IDC3_PKBUTTON);
1679 radioline(&cp, "Preferred SSH protocol version:",
1680 IDC3_SSHPROTSTATIC, 2,
1681 "&1", IDC3_SSHPROT1, "&2", IDC3_SSHPROT2, NULL);
1682 radioline(&cp, "Preferred encryption algorithm:", IDC3_CIPHERSTATIC, 3,
1683 "&3DES", IDC3_CIPHER3DES,
1684 "&Blowfish", IDC3_CIPHERBLOWF,
1685 "&DES", IDC3_CIPHERDES, NULL);
1687 SetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype);
1688 SetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username);
1689 CheckDlgButton (hwnd, IDC3_NOPTY, cfg.nopty);
1690 CheckDlgButton (hwnd, IDC3_AGENTFWD, cfg.agentfwd);
1691 CheckRadioButton (hwnd, IDC3_CIPHER3DES, IDC3_CIPHERDES,
1692 cfg.cipher == CIPHER_BLOWFISH ? IDC3_CIPHERBLOWF :
1693 cfg.cipher == CIPHER_DES ? IDC3_CIPHERDES :
1695 CheckRadioButton (hwnd, IDC3_SSHPROT1, IDC3_SSHPROT2,
1696 cfg.sshprot == 1 ? IDC3_SSHPROT1 : IDC3_SSHPROT2);
1697 CheckDlgButton (hwnd, IDC3_AUTHTIS, cfg.try_tis_auth);
1698 SetDlgItemText (hwnd, IDC3_PKEDIT, cfg.keyfile);
1699 SetDlgItemText (hwnd, IDC3_CMDEDIT, cfg.remote_cmd);
1702 switch (LOWORD(wParam)) {
1704 if (HIWORD(wParam) == EN_CHANGE)
1705 GetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype,
1706 sizeof(cfg.termtype)-1);
1709 if (HIWORD(wParam) == EN_CHANGE)
1710 GetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username,
1711 sizeof(cfg.username)-1);
1714 if (HIWORD(wParam) == BN_CLICKED ||
1715 HIWORD(wParam) == BN_DOUBLECLICKED)
1716 cfg.nopty = IsDlgButtonChecked (hwnd, IDC3_NOPTY);
1719 if (HIWORD(wParam) == BN_CLICKED ||
1720 HIWORD(wParam) == BN_DOUBLECLICKED)
1721 cfg.agentfwd = IsDlgButtonChecked (hwnd, IDC3_AGENTFWD);
1723 case IDC3_CIPHER3DES:
1724 case IDC3_CIPHERBLOWF:
1725 case IDC3_CIPHERDES:
1726 if (HIWORD(wParam) == BN_CLICKED ||
1727 HIWORD(wParam) == BN_DOUBLECLICKED) {
1728 if (IsDlgButtonChecked (hwnd, IDC3_CIPHER3DES))
1729 cfg.cipher = CIPHER_3DES;
1730 else if (IsDlgButtonChecked (hwnd, IDC3_CIPHERBLOWF))
1731 cfg.cipher = CIPHER_BLOWFISH;
1732 else if (IsDlgButtonChecked (hwnd, IDC3_CIPHERDES))
1733 cfg.cipher = CIPHER_DES;
1738 if (HIWORD(wParam) == BN_CLICKED ||
1739 HIWORD(wParam) == BN_DOUBLECLICKED) {
1740 if (IsDlgButtonChecked (hwnd, IDC3_SSHPROT1))
1742 else if (IsDlgButtonChecked (hwnd, IDC3_SSHPROT2))
1747 if (HIWORD(wParam) == BN_CLICKED ||
1748 HIWORD(wParam) == BN_DOUBLECLICKED)
1749 cfg.try_tis_auth = IsDlgButtonChecked (hwnd, IDC3_AUTHTIS);
1752 if (HIWORD(wParam) == EN_CHANGE)
1753 GetDlgItemText (hwnd, IDC3_PKEDIT, cfg.keyfile,
1754 sizeof(cfg.keyfile)-1);
1757 if (HIWORD(wParam) == EN_CHANGE)
1758 GetDlgItemText (hwnd, IDC3_CMDEDIT, cfg.remote_cmd,
1759 sizeof(cfg.remote_cmd)-1);
1763 * FIXME: this crashes. Find out why.
1765 memset(&of, 0, sizeof(of));
1766 #ifdef OPENFILENAME_SIZE_VERSION_400
1767 of.lStructSize = OPENFILENAME_SIZE_VERSION_400;
1769 of.lStructSize = sizeof(of);
1771 of.hwndOwner = hwnd;
1772 of.lpstrFilter = "All Files\0*\0\0\0";
1773 of.lpstrCustomFilter = NULL;
1774 of.nFilterIndex = 1;
1775 of.lpstrFile = filename; strcpy(filename, cfg.keyfile);
1776 of.nMaxFile = sizeof(filename);
1777 of.lpstrFileTitle = NULL;
1778 of.lpstrInitialDir = NULL;
1779 of.lpstrTitle = "Select Public Key File";
1781 if (GetOpenFileName(&of)) {
1782 strcpy(cfg.keyfile, filename);
1783 SetDlgItemText (hwnd, IDC3_PKEDIT, cfg.keyfile);
1789 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1792 static int CALLBACK SelectionProc (HWND hwnd, UINT msg,
1793 WPARAM wParam, LPARAM lParam) {
1799 /* Accelerators used: [aco] stwx */
1800 ctlposinit(&cp, hwnd);
1801 radiobig(&cp, "Action of mouse buttons:", IDC4_MBSTATIC,
1802 "&Windows (Right pastes, Middle extends)", IDC4_MBWINDOWS,
1803 "&xterm (Right extends, Middle pastes)", IDC4_MBXTERM,
1805 charclass(&cp, "Character classes:", IDC4_CCSTATIC, IDC4_CCLIST,
1806 "&Set", IDC4_CCSET, IDC4_CCEDIT,
1807 "&to class", IDC4_CCSTATIC2);
1809 CheckRadioButton (hwnd, IDC4_MBWINDOWS, IDC4_MBXTERM,
1810 cfg.mouse_is_xterm ? IDC4_MBXTERM : IDC4_MBWINDOWS);
1812 static int tabs[4] = {25, 61, 96, 128};
1813 SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_SETTABSTOPS, 4,
1816 for (i=0; i<256; i++) {
1818 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
1819 (i>=0x21 && i != 0x7F) ? i : ' ',
1821 SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_ADDSTRING, 0,
1826 switch (LOWORD(wParam)) {
1827 case IDC4_MBWINDOWS:
1829 cfg.mouse_is_xterm = IsDlgButtonChecked (hwnd, IDC4_MBXTERM);
1835 int n = GetDlgItemInt (hwnd, IDC4_CCEDIT, &ok, FALSE);
1840 for (i=0; i<256; i++)
1841 if (SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_GETSEL,
1844 cfg.wordness[i] = n;
1845 SendDlgItemMessage (hwnd, IDC4_CCLIST,
1846 LB_DELETESTRING, i, 0);
1847 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
1848 (i>=0x21 && i != 0x7F) ? i : ' ',
1850 SendDlgItemMessage (hwnd, IDC4_CCLIST,
1860 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1863 static int CALLBACK ColourProc (HWND hwnd, UINT msg,
1864 WPARAM wParam, LPARAM lParam) {
1865 static const char *const colours[] = {
1866 "Default Foreground", "Default Bold Foreground",
1867 "Default Background", "Default Bold Background",
1868 "Cursor Text", "Cursor Colour",
1869 "ANSI Black", "ANSI Black Bold",
1870 "ANSI Red", "ANSI Red Bold",
1871 "ANSI Green", "ANSI Green Bold",
1872 "ANSI Yellow", "ANSI Yellow Bold",
1873 "ANSI Blue", "ANSI Blue Bold",
1874 "ANSI Magenta", "ANSI Magenta Bold",
1875 "ANSI Cyan", "ANSI Cyan Bold",
1876 "ANSI White", "ANSI White Bold"
1878 static const int permanent[] = {
1879 TRUE, FALSE, TRUE, FALSE, TRUE, TRUE,
1880 TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE,
1881 TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE
1887 /* Accelerators used: [aco] bmlu */
1888 ctlposinit(&cp, hwnd);
1889 checkbox(&cp, "&Bolded text is a different colour", IDC5_BOLDCOLOUR);
1890 checkbox(&cp, "Attempt to use &logical palettes", IDC5_PALETTE);
1891 colouredit(&cp, "Select a colo&ur and click to modify it:",
1892 IDC5_STATIC, IDC5_LIST,
1893 "&Modify...", IDC5_CHANGE,
1894 "Red:", IDC5_RSTATIC, IDC5_RVALUE,
1895 "Green:", IDC5_GSTATIC, IDC5_GVALUE,
1896 "Blue:", IDC5_BSTATIC, IDC5_BVALUE, NULL);
1898 CheckDlgButton (hwnd, IDC5_BOLDCOLOUR, cfg.bold_colour);
1899 CheckDlgButton (hwnd, IDC5_PALETTE, cfg.try_palette);
1902 for (i=0; i<22; i++)
1903 if (cfg.bold_colour || permanent[i])
1904 SendDlgItemMessage (hwnd, IDC5_LIST, LB_ADDSTRING, 0,
1905 (LPARAM) colours[i]);
1907 SendDlgItemMessage (hwnd, IDC5_LIST, LB_SETCURSEL, 0, 0);
1908 SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[0][0], FALSE);
1909 SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[0][1], FALSE);
1910 SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[0][2], FALSE);
1913 switch (LOWORD(wParam)) {
1914 case IDC5_BOLDCOLOUR:
1915 if (HIWORD(wParam) == BN_CLICKED ||
1916 HIWORD(wParam) == BN_DOUBLECLICKED) {
1918 cfg.bold_colour = IsDlgButtonChecked (hwnd, IDC5_BOLDCOLOUR);
1919 n = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCOUNT, 0, 0);
1920 if (cfg.bold_colour && n!=22) {
1921 for (i=0; i<22; i++)
1923 SendDlgItemMessage (hwnd, IDC5_LIST,
1925 (LPARAM) colours[i]);
1926 } else if (!cfg.bold_colour && n!=12) {
1929 SendDlgItemMessage (hwnd, IDC5_LIST,
1930 LB_DELETESTRING, i, 0);
1935 if (HIWORD(wParam) == BN_CLICKED ||
1936 HIWORD(wParam) == BN_DOUBLECLICKED)
1937 cfg.try_palette = IsDlgButtonChecked (hwnd, IDC5_PALETTE);
1940 if (HIWORD(wParam) == LBN_DBLCLK ||
1941 HIWORD(wParam) == LBN_SELCHANGE) {
1942 int i = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCURSEL,
1944 if (!cfg.bold_colour)
1945 i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
1946 SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[i][0], FALSE);
1947 SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[i][1], FALSE);
1948 SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[i][2], FALSE);
1952 if (HIWORD(wParam) == BN_CLICKED ||
1953 HIWORD(wParam) == BN_DOUBLECLICKED) {
1954 static CHOOSECOLOR cc;
1955 static DWORD custom[16] = {0}; /* zero initialisers */
1956 int i = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCURSEL,
1958 if (!cfg.bold_colour)
1959 i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
1960 cc.lStructSize = sizeof(cc);
1961 cc.hwndOwner = hwnd;
1962 cc.hInstance = (HWND)hinst;
1963 cc.lpCustColors = custom;
1964 cc.rgbResult = RGB (cfg.colours[i][0], cfg.colours[i][1],
1966 cc.Flags = CC_FULLOPEN | CC_RGBINIT;
1967 if (ChooseColor(&cc)) {
1969 (unsigned char) (cc.rgbResult & 0xFF);
1971 (unsigned char) (cc.rgbResult >> 8) & 0xFF;
1973 (unsigned char) (cc.rgbResult >> 16) & 0xFF;
1974 SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[i][0],
1976 SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[i][1],
1978 SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[i][2],
1986 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1989 static int CALLBACK TranslationProc (HWND hwnd, UINT msg,
1990 WPARAM wParam, LPARAM lParam) {
1995 /* Accelerators used: [aco] beiknpsx */
1996 ctlposinit(&cp, hwnd);
1998 "Handling of VT100 line drawing characters:", IDC2_VTSTATIC,
1999 "Font has &XWindows encoding", IDC2_VTXWINDOWS,
2000 "Use font in &both ANSI and OEM modes", IDC2_VTOEMANSI,
2001 "Use font in O&EM mode only", IDC2_VTOEMONLY,
2002 "&Poor man's line drawing (""+"", ""-"" and ""|"")",
2003 IDC2_VTPOORMAN, NULL);
2005 "Character set translation:", IDC6_XLATSTATIC,
2006 "&None", IDC6_NOXLAT,
2007 "&KOI8 / Win-1251", IDC6_KOI8WIN1251,
2008 "&ISO-8859-2 / Win-1250", IDC6_88592WIN1250, NULL);
2009 checkbox(&cp, "CAP&S LOCK acts as cyrillic switch", IDC6_CAPSLOCKCYR);
2011 CheckRadioButton (hwnd, IDC6_NOXLAT, IDC6_88592WIN1250,
2012 cfg.xlat_88592w1250 ? IDC6_88592WIN1250 :
2013 cfg.xlat_enablekoiwin ? IDC6_KOI8WIN1251 :
2015 CheckDlgButton (hwnd, IDC6_CAPSLOCKCYR, cfg.xlat_capslockcyr);
2016 CheckRadioButton (hwnd, IDC2_VTXWINDOWS, IDC2_VTPOORMAN,
2017 cfg.vtmode == VT_XWINDOWS ? IDC2_VTXWINDOWS :
2018 cfg.vtmode == VT_OEMANSI ? IDC2_VTOEMANSI :
2019 cfg.vtmode == VT_OEMONLY ? IDC2_VTOEMONLY :
2022 switch (LOWORD(wParam)) {
2024 case IDC6_KOI8WIN1251:
2025 case IDC6_88592WIN1250:
2026 cfg.xlat_enablekoiwin =
2027 IsDlgButtonChecked (hwnd, IDC6_KOI8WIN1251);
2028 cfg.xlat_88592w1250 =
2029 IsDlgButtonChecked (hwnd, IDC6_88592WIN1250);
2031 case IDC6_CAPSLOCKCYR:
2032 if (HIWORD(wParam) == BN_CLICKED ||
2033 HIWORD(wParam) == BN_DOUBLECLICKED) {
2034 cfg.xlat_capslockcyr =
2035 IsDlgButtonChecked (hwnd, IDC6_CAPSLOCKCYR);
2038 case IDC2_VTXWINDOWS:
2039 case IDC2_VTOEMANSI:
2040 case IDC2_VTOEMONLY:
2041 case IDC2_VTPOORMAN:
2043 (IsDlgButtonChecked (hwnd, IDC2_VTXWINDOWS) ? VT_XWINDOWS :
2044 IsDlgButtonChecked (hwnd, IDC2_VTOEMANSI) ? VT_OEMANSI :
2045 IsDlgButtonChecked (hwnd, IDC2_VTOEMONLY) ? VT_OEMONLY :
2050 return GeneralPanelProc (hwnd, msg, wParam, lParam);
2053 static DLGPROC panelproc[NPANELS] = {
2054 ConnectionProc, KeyboardProc, TerminalProc, WindowProc,
2055 TelnetProc, SshProc, SelectionProc, ColourProc, TranslationProc
2057 static char *panelids[NPANELS] = {
2058 MAKEINTRESOURCE(IDD_PANEL0),
2059 MAKEINTRESOURCE(IDD_PANEL1),
2060 MAKEINTRESOURCE(IDD_PANEL2),
2061 MAKEINTRESOURCE(IDD_PANELW),
2062 MAKEINTRESOURCE(IDD_PANEL3),
2063 MAKEINTRESOURCE(IDD_PANEL35),
2064 MAKEINTRESOURCE(IDD_PANEL4),
2065 MAKEINTRESOURCE(IDD_PANEL5),
2066 MAKEINTRESOURCE(IDD_PANEL6)
2069 static char *names[NPANELS] = {
2070 "Connection", "Keyboard", "Terminal", "Window", "Telnet",
2071 "SSH", "Selection", "Colours", "Translation"
2074 static int mainp[MAIN_NPANELS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8};
2075 static int reconfp[RECONF_NPANELS] = { 1, 2, 3, 6, 7, 8};
2077 static HWND makesubdialog(HWND hwnd, int x, int y, int w, int h, int n) {
2081 r.left = x; r.top = y;
2082 r.right = r.left + w; r.bottom = r.top + h;
2083 MapDialogRect(hwnd, &r);
2084 ret = CreateWindowEx(WS_EX_CONTROLPARENT,
2085 WC_DIALOG, "", /* no title */
2086 WS_CHILD | WS_VISIBLE | DS_SETFONT,
2088 r.right-r.left, r.bottom-r.top,
2089 hwnd, (HMENU)(panelids[n]),
2091 SetWindowLong (ret, DWL_DLGPROC, (LONG)panelproc[n]);
2092 font = SendMessage(hwnd, WM_GETFONT, 0, 0);
2093 SendMessage (ret, WM_SETFONT, font, MAKELPARAM(0, 0));
2094 SendMessage (ret, WM_INITDIALOG, 0, 0);
2098 static int GenericMainDlgProc (HWND hwnd, UINT msg,
2099 WPARAM wParam, LPARAM lParam,
2100 int npanels, int *panelnums, HWND *page) {
2105 { /* centre the window */
2108 hw = GetDesktopWindow();
2109 if (GetWindowRect (hw, &rs) && GetWindowRect (hwnd, &rd))
2110 MoveWindow (hwnd, (rs.right + rs.left + rd.left - rd.right)/2,
2111 (rs.bottom + rs.top + rd.top - rd.bottom)/2,
2112 rd.right-rd.left, rd.bottom-rd.top, TRUE);
2116 r.left = 3; r.right = r.left + 174;
2117 r.top = 3; r.bottom = r.top + 193;
2118 MapDialogRect(hwnd, &r);
2119 tabctl = CreateWindowEx(0, WC_TABCONTROL, "",
2120 WS_CHILD | WS_VISIBLE |
2121 WS_TABSTOP | TCS_MULTILINE,
2123 r.right-r.left, r.bottom-r.top,
2124 hwnd, (HMENU)IDC_TAB, hinst, NULL);
2128 ctlposinit2(&cp, hwnd);
2129 ersatztab(&cp, "Category:", IDC_TABSTATIC1, IDC_TABLIST,
2132 WPARAM font = SendMessage(hwnd, WM_GETFONT, 0, 0);
2133 SendMessage(tabctl, WM_SETFONT, font, MAKELPARAM(TRUE, 0));
2137 if (tabctl) { /* initialise the tab control */
2141 for (i=0; i<npanels; i++) {
2142 tab.mask = TCIF_TEXT;
2143 tab.pszText = names[panelnums[i]];
2144 TabCtrl_InsertItem (tabctl, i, &tab);
2149 for (i=0; i<npanels; i++) {
2150 SendDlgItemMessage(hwnd, IDC_TABLIST, CB_ADDSTRING,
2151 0, (LPARAM)names[panelnums[i]]);
2153 SendDlgItemMessage(hwnd, IDC_TABLIST, CB_SETCURSEL, 0, 0);
2155 *page = makesubdialog(hwnd, 6, 30, 168, 163, panelnums[0]);
2159 if (LOWORD(wParam) == IDC_TAB &&
2160 ((LPNMHDR)lParam)->code == TCN_SELCHANGE) {
2161 int i = TabCtrl_GetCurSel(((LPNMHDR)lParam)->hwndFrom);
2163 DestroyWindow (*page);
2164 *page = makesubdialog(hwnd, 6, 30, 168, 163, panelnums[i]);
2165 SetFocus (((LPNMHDR)lParam)->hwndFrom); /* ensure focus stays */
2170 switch (LOWORD(wParam)) {
2172 if (HIWORD(wParam) == CBN_SELCHANGE) {
2173 HWND tablist = GetDlgItem (hwnd, IDC_TABLIST);
2174 int i = SendMessage (tablist, CB_GETCURSEL, 0, 0);
2176 DestroyWindow (*page);
2177 *page = makesubdialog(hwnd, 6, 30, 168, 163, panelnums[i]);
2178 SetFocus(tablist); /* ensure focus stays */
2184 EndDialog (hwnd, 1);
2189 EndDialog (hwnd, 0);
2194 EndDialog (hwnd, 0);
2197 /* Grrr Explorer will maximize Dialogs! */
2199 if (wParam == SIZE_MAXIMIZED)
2206 static int CALLBACK MainDlgProc (HWND hwnd, UINT msg,
2207 WPARAM wParam, LPARAM lParam) {
2212 static HWND page = NULL;
2214 if (msg == WM_COMMAND && LOWORD(wParam) == IDOK) {
2217 * If the Connection panel is active and the Session List
2218 * box is selected, we treat a press of Open to have an
2219 * implicit press of Load preceding it.
2221 hw = GetDlgItem (hwnd, IDC_TAB);
2222 i = TabCtrl_GetCurSel(hw);
2223 if (panelproc[mainp[i]] == ConnectionProc &&
2224 page && implicit_load_ok) {
2225 SendMessage (page, WM_COMMAND,
2226 MAKELONG(IDC0_SESSLOAD, BN_CLICKED), 0);
2230 if (msg == WM_COMMAND && LOWORD(wParam) == IDC_ABOUT) {
2231 EnableWindow(hwnd, 0);
2232 DialogBox(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
2233 GetParent(hwnd), AboutProc);
2234 EnableWindow(hwnd, 1);
2235 SetActiveWindow(hwnd);
2237 return GenericMainDlgProc (hwnd, msg, wParam, lParam,
2238 MAIN_NPANELS, mainp, &page);
2241 static int CALLBACK ReconfDlgProc (HWND hwnd, UINT msg,
2242 WPARAM wParam, LPARAM lParam) {
2244 return GenericMainDlgProc (hwnd, msg, wParam, lParam,
2245 RECONF_NPANELS, reconfp, &page);
2248 void get_sesslist(int allocate) {
2249 static char otherbuf[2048];
2250 static char *buffer;
2251 int buflen, bufsize, i;
2257 if ((handle = enum_settings_start()) == NULL)
2260 buflen = bufsize = 0;
2263 ret = enum_settings_next(handle, otherbuf, sizeof(otherbuf));
2265 int len = strlen(otherbuf)+1;
2266 if (bufsize < buflen+len) {
2267 bufsize = buflen + len + 2048;
2268 buffer = srealloc(buffer, bufsize);
2270 strcpy(buffer+buflen, otherbuf);
2271 buflen += strlen(buffer+buflen)+1;
2274 enum_settings_finish(handle);
2275 buffer = srealloc(buffer, buflen+1);
2276 buffer[buflen] = '\0';
2279 nsessions = 1; /* "Default Settings" counts as one */
2281 if (strcmp(p, "Default Settings"))
2287 sessions = smalloc(nsessions * sizeof(char *));
2288 sessions[0] = "Default Settings";
2292 if (strcmp(p, "Default Settings"))
2303 int do_config (void) {
2307 savedsession[0] = '\0';
2308 ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_MAINBOX), NULL, MainDlgProc);
2309 get_sesslist(FALSE);
2314 int do_reconfig (HWND hwnd) {
2318 backup_cfg = cfg; /* structure copy */
2319 ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_RECONF), hwnd, ReconfDlgProc);
2321 cfg = backup_cfg; /* structure copy */
2328 void do_defaults (char *session) {
2330 load_settings (session, TRUE);
2332 load_settings ("Default Settings", FALSE);
2335 void logevent (char *string) {
2336 if (nevents >= negsize) {
2338 events = srealloc (events, negsize * sizeof(*events));
2340 events[nevents] = smalloc(1+strlen(string));
2341 strcpy (events[nevents], string);
2345 SendDlgItemMessage (logbox, IDN_LIST, LB_ADDSTRING,
2347 count = SendDlgItemMessage (logbox, IDN_LIST, LB_GETCOUNT, 0, 0);
2348 SendDlgItemMessage (logbox, IDN_LIST, LB_SETTOPINDEX, count-1, 0);
2352 void showeventlog (HWND hwnd) {
2354 logbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_LOGBOX),
2356 ShowWindow (logbox, SW_SHOWNORMAL);
2360 void showabout (HWND hwnd) {
2362 abtbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
2364 ShowWindow (abtbox, SW_SHOWNORMAL);
2368 void verify_ssh_host_key(char *host, int port, char *keytype,
2369 char *keystr, char *fingerprint) {
2372 static const char absentmsg[] =
2373 "The server's host key is not cached in the registry. You\n"
2374 "have no guarantee that the server is the computer you\n"
2376 "The server's key fingerprint is:\n"
2378 "If you trust this host, hit Yes to add the key to\n"
2379 "PuTTY's cache and carry on connecting.\n"
2380 "If you do not trust this host, hit No to abandon the\n"
2383 static const char wrongmsg[] =
2384 "WARNING - POTENTIAL SECURITY BREACH!\n"
2386 "The server's host key does not match the one PuTTY has\n"
2387 "cached in the registry. This means that either the\n"
2388 "server administrator has changed the host key, or you\n"
2389 "have actually connected to another computer pretending\n"
2390 "to be the server.\n"
2391 "The new key fingerprint is:\n"
2393 "If you were expecting this change and trust the new key,\n"
2394 "hit Yes to update PuTTY's cache and continue connecting.\n"
2395 "If you want to carry on connecting but without updating\n"
2396 "the cache, hit No.\n"
2397 "If you want to abandon the connection completely, hit\n"
2398 "Cancel. Hitting Cancel is the ONLY guaranteed safe\n"
2401 static const char mbtitle[] = "PuTTY Security Alert";
2404 char message[160+ /* sensible fingerprint max size */
2405 (sizeof(absentmsg) > sizeof(wrongmsg) ?
2406 sizeof(absentmsg) : sizeof(wrongmsg))];
2409 * Verify the key against the registry.
2411 ret = verify_host_key(host, port, keytype, keystr);
2413 if (ret == 0) /* success - key matched OK */
2415 if (ret == 2) { /* key was different */
2417 sprintf(message, wrongmsg, fingerprint);
2418 mbret = MessageBox(NULL, message, mbtitle,
2419 MB_ICONWARNING | MB_YESNOCANCEL);
2421 store_host_key(host, port, keytype, keystr);
2422 if (mbret == IDCANCEL)
2425 if (ret == 1) { /* key was absent */
2427 sprintf(message, absentmsg, fingerprint);
2428 mbret = MessageBox(NULL, message, mbtitle,
2429 MB_ICONWARNING | MB_YESNO);
2432 store_host_key(host, port, keytype, keystr);