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]);
334 /* case WM_CTLCOLORDLG: */
335 /* return (int) GetStockObject (LTGRAY_BRUSH); */
337 switch (LOWORD(wParam)) {
340 DestroyWindow (hwnd);
343 if (HIWORD(wParam) == BN_CLICKED ||
344 HIWORD(wParam) == BN_DOUBLECLICKED) {
347 selcount = SendDlgItemMessage(hwnd, IDN_LIST,
348 LB_GETSELCOUNT, 0, 0);
349 selitems = malloc(selcount * sizeof(int));
351 int count = SendDlgItemMessage(hwnd, IDN_LIST,
353 selcount, (LPARAM)selitems);
357 static unsigned char sel_nl[] = SEL_NL;
360 for (i = 0; i < count; i++)
361 size += strlen(events[selitems[i]]) + sizeof(sel_nl);
363 clipdata = malloc(size);
366 for (i = 0; i < count; i++) {
367 char *q = events[selitems[i]];
368 int qlen = strlen(q);
371 memcpy(p, sel_nl, sizeof(sel_nl));
374 write_clip(clipdata, size);
386 DestroyWindow (hwnd);
392 static int CALLBACK LicenceProc (HWND hwnd, UINT msg,
393 WPARAM wParam, LPARAM lParam) {
398 switch (LOWORD(wParam)) {
411 static int CALLBACK AboutProc (HWND hwnd, UINT msg,
412 WPARAM wParam, LPARAM lParam) {
415 SetDlgItemText (hwnd, IDA_VERSION, ver);
417 /* case WM_CTLCOLORDLG: */
418 /* return (int) GetStockObject (LTGRAY_BRUSH); */
419 /* case WM_CTLCOLORSTATIC: */
420 /* SetBkColor ((HDC)wParam, RGB(192,192,192)); */
421 /* return (int) GetStockObject (LTGRAY_BRUSH); */
423 switch (LOWORD(wParam)) {
426 DestroyWindow (hwnd);
429 EnableWindow(hwnd, 0);
430 DialogBox (hinst, MAKEINTRESOURCE(IDD_LICENCEBOX),
432 EnableWindow(hwnd, 1);
433 SetActiveWindow(hwnd);
439 DestroyWindow (hwnd);
445 /* ----------------------------------------------------------------------
446 * Routines to self-manage the controls in a dialog box.
452 #define STATICHEIGHT 8
453 #define CHECKBOXHEIGHT 8
454 #define RADIOHEIGHT 8
455 #define EDITHEIGHT 12
456 #define COMBOHEIGHT 12
457 #define PUSHBTNHEIGHT 14
466 /* Used on self-constructed dialogs. */
467 void ctlposinit(struct ctlpos *cp, HWND hwnd) {
470 cp->units = GetWindowLong(hwnd, GWL_USERDATA);
471 cp->font = GetWindowLong(hwnd, DWL_USER);
472 cp->ypos = GAPBETWEEN;
473 GetClientRect(hwnd, &r);
474 cp->width = (r.right * 4) / (cp->units & 0xFFFF) - 2*GAPBETWEEN;
477 /* Used on kosher dialogs. */
478 void ctlposinit2(struct ctlpos *cp, HWND hwnd) {
484 MapDialogRect(hwnd, &r);
485 cp->units = (r.bottom << 16) | r.right;
486 cp->font = SendMessage(hwnd, WM_GETFONT, 0, 0);
487 cp->ypos = GAPBETWEEN;
488 GetClientRect(hwnd, &r);
489 cp->width = (r.right * 4) / (cp->units & 0xFFFF) - 2*GAPBETWEEN;
492 void doctl(struct ctlpos *cp, RECT r, char *wclass, int wstyle, int exstyle,
493 char *wtext, int wid) {
496 * Note nonstandard use of RECT. This is deliberate: by
497 * transforming the width and height directly we arrange to
498 * have all supposedly same-sized controls really same-sized.
501 /* MapDialogRect, or its near equivalent. */
502 r.left = (r.left * (cp->units & 0xFFFF)) / 4;
503 r.right = (r.right * (cp->units & 0xFFFF)) / 4;
504 r.top = (r.top * ((cp->units>>16) & 0xFFFF)) / 8;
505 r.bottom = (r.bottom * ((cp->units>>16) & 0xFFFF)) / 8;
507 ctl = CreateWindowEx(exstyle, wclass, wtext, wstyle,
508 r.left, r.top, r.right, r.bottom,
509 cp->hwnd, (HMENU)wid, hinst, NULL);
510 SendMessage(ctl, WM_SETFONT, cp->font, MAKELPARAM(TRUE, 0));
514 * Some edit boxes. Each one has a static above it. The percentages
515 * of the horizontal space are provided.
517 void multiedit(struct ctlpos *cp, ...) {
526 int staticid, editid, pcwidth;
527 text = va_arg(ap, char *);
530 staticid = va_arg(ap, int);
531 editid = va_arg(ap, int);
532 pcwidth = va_arg(ap, int);
534 r.left = xpos + GAPBETWEEN;
536 xpos = (cp->width + GAPBETWEEN) * percent / 100;
537 r.right = xpos - r.left;
539 r.top = cp->ypos; r.bottom = STATICHEIGHT;
540 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0,
542 r.top = cp->ypos + 8 + GAPWITHIN; r.bottom = EDITHEIGHT;
544 WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
549 cp->ypos += 8+GAPWITHIN+12+GAPBETWEEN;
553 * A set of radio buttons on the same line, with a static above
554 * them. `nacross' dictates how many parts the line is divided into
555 * (you might want this not to equal the number of buttons if you
556 * needed to line up some 2s and some 3s to look good in the same
559 void radioline(struct ctlpos *cp, char *text, int id, int nacross, ...) {
565 r.left = GAPBETWEEN; r.top = cp->ypos;
566 r.right = cp->width; r.bottom = STATICHEIGHT;
567 cp->ypos += r.bottom + GAPWITHIN;
568 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, text, id);
569 va_start(ap, nacross);
575 btext = va_arg(ap, char *);
578 bid = va_arg(ap, int);
579 r.left = GAPBETWEEN + i * (cp->width+GAPBETWEEN)/nacross;
580 r.right = (i+1) * (cp->width+GAPBETWEEN)/nacross - r.left;
581 r.top = cp->ypos; r.bottom = RADIOHEIGHT;
582 doctl(cp, r, "BUTTON",
583 BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP | group,
590 cp->ypos += r.bottom + GAPBETWEEN;
594 * A set of radio buttons on multiple lines, with a static above
597 void radiobig(struct ctlpos *cp, char *text, int id, ...) {
602 r.left = GAPBETWEEN; r.top = cp->ypos;
603 r.right = cp->width; r.bottom = STATICHEIGHT;
604 cp->ypos += r.bottom + GAPWITHIN;
605 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, text, id);
611 btext = va_arg(ap, char *);
614 bid = va_arg(ap, int);
615 r.left = GAPBETWEEN; r.top = cp->ypos;
616 r.right = cp->width; r.bottom = STATICHEIGHT;
617 cp->ypos += r.bottom + GAPWITHIN;
618 doctl(cp, r, "BUTTON",
619 BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP | group,
625 cp->ypos += GAPBETWEEN - GAPWITHIN;
629 * A single standalone checkbox.
631 void checkbox(struct ctlpos *cp, char *text, int id) {
634 r.left = GAPBETWEEN; r.top = cp->ypos;
635 r.right = cp->width; r.bottom = CHECKBOXHEIGHT;
636 cp->ypos += r.bottom + GAPBETWEEN;
637 doctl(cp, r, "BUTTON",
638 BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0,
643 * A button on the right hand side, with a static to its left.
645 void staticbtn(struct ctlpos *cp, char *stext, int sid, char *btext, int bid) {
646 const int height = (PUSHBTNHEIGHT > STATICHEIGHT ?
647 PUSHBTNHEIGHT : STATICHEIGHT);
649 int lwid, rwid, rpos;
651 rpos = GAPBETWEEN + 3 * (cp->width + GAPBETWEEN) / 4;
652 lwid = rpos - 2*GAPBETWEEN;
653 rwid = cp->width + GAPBETWEEN - rpos;
655 r.left = GAPBETWEEN; r.top = cp->ypos + (height-STATICHEIGHT)/2;
656 r.right = lwid; r.bottom = STATICHEIGHT;
657 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
659 r.left = rpos; r.top = cp->ypos + (height-PUSHBTNHEIGHT)/2;
660 r.right = rwid; r.bottom = PUSHBTNHEIGHT;
661 doctl(cp, r, "BUTTON",
662 WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
666 cp->ypos += height + GAPBETWEEN;
670 * An edit control on the right hand side, with a static to its left.
672 void staticedit(struct ctlpos *cp, char *stext, int sid, int eid) {
673 const int height = (EDITHEIGHT > STATICHEIGHT ?
674 EDITHEIGHT : STATICHEIGHT);
676 int lwid, rwid, rpos;
678 rpos = GAPBETWEEN + (cp->width + GAPBETWEEN) / 2;
679 lwid = rpos - 2*GAPBETWEEN;
680 rwid = cp->width + GAPBETWEEN - rpos;
682 r.left = GAPBETWEEN; r.top = cp->ypos + (height-STATICHEIGHT)/2;
683 r.right = lwid; r.bottom = STATICHEIGHT;
684 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
686 r.left = rpos; r.top = cp->ypos + (height-EDITHEIGHT)/2;
687 r.right = rwid; r.bottom = EDITHEIGHT;
689 WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
693 cp->ypos += height + GAPBETWEEN;
697 * A tab-control substitute when a real tab control is unavailable.
699 void ersatztab(struct ctlpos *cp, char *stext, int sid, int lid, int s2id) {
700 const int height = (COMBOHEIGHT > STATICHEIGHT ?
701 COMBOHEIGHT : STATICHEIGHT);
703 int bigwid, lwid, rwid, rpos;
704 static const int BIGGAP = 15;
705 static const int MEDGAP = 3;
707 bigwid = cp->width + 2*GAPBETWEEN - 2*BIGGAP;
709 rpos = BIGGAP + (bigwid + BIGGAP) / 2;
710 lwid = rpos - 2*BIGGAP;
711 rwid = bigwid + BIGGAP - rpos;
713 r.left = BIGGAP; r.top = cp->ypos + (height-STATICHEIGHT)/2;
714 r.right = lwid; r.bottom = STATICHEIGHT;
715 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
717 r.left = rpos; r.top = cp->ypos + (height-COMBOHEIGHT)/2;
718 r.right = rwid; r.bottom = COMBOHEIGHT*10;
719 doctl(cp, r, "COMBOBOX",
720 WS_CHILD | WS_VISIBLE | WS_TABSTOP |
721 CBS_DROPDOWNLIST | CBS_HASSTRINGS,
725 cp->ypos += height + MEDGAP + GAPBETWEEN;
727 r.left = GAPBETWEEN; r.top = cp->ypos;
728 r.right = cp->width; r.bottom = 2;
729 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE | SS_ETCHEDHORZ,
734 * A static line, followed by an edit control on the left hand side
735 * and a button on the right.
737 void editbutton(struct ctlpos *cp, char *stext, int sid,
738 int eid, char *btext, int bid) {
739 const int height = (EDITHEIGHT > PUSHBTNHEIGHT ?
740 EDITHEIGHT : PUSHBTNHEIGHT);
742 int lwid, rwid, rpos;
744 r.left = GAPBETWEEN; r.top = cp->ypos;
745 r.right = cp->width; r.bottom = STATICHEIGHT;
746 cp->ypos += r.bottom + GAPWITHIN;
747 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
749 rpos = GAPBETWEEN + 3 * (cp->width + GAPBETWEEN) / 4;
750 lwid = rpos - 2*GAPBETWEEN;
751 rwid = cp->width + GAPBETWEEN - rpos;
753 r.left = GAPBETWEEN; r.top = cp->ypos + (height-EDITHEIGHT)/2;
754 r.right = lwid; r.bottom = EDITHEIGHT;
756 WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
760 r.left = rpos; r.top = cp->ypos + (height-PUSHBTNHEIGHT)/2;
761 r.right = rwid; r.bottom = PUSHBTNHEIGHT;
762 doctl(cp, r, "BUTTON",
763 WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
767 cp->ypos += height + GAPBETWEEN;
771 * Special control which was hard to describe generically: the
772 * session-saver assembly. A static; below that an edit box; below
773 * that a list box. To the right of the list box, a column of
776 void sesssaver(struct ctlpos *cp, char *text,
777 int staticid, int editid, int listid, ...) {
780 int lwid, rwid, rpos;
782 const int LISTDEFHEIGHT = 66;
784 rpos = GAPBETWEEN + 3 * (cp->width + GAPBETWEEN) / 4;
785 lwid = rpos - 2*GAPBETWEEN;
786 rwid = cp->width + GAPBETWEEN - rpos;
788 /* The static control. */
789 r.left = GAPBETWEEN; r.top = cp->ypos;
790 r.right = lwid; r.bottom = STATICHEIGHT;
791 cp->ypos += r.bottom + GAPWITHIN;
792 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, text, staticid);
794 /* The edit control. */
795 r.left = GAPBETWEEN; r.top = cp->ypos;
796 r.right = lwid; r.bottom = EDITHEIGHT;
797 cp->ypos += r.bottom + GAPWITHIN;
799 WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
804 * The buttons (we should hold off on the list box until we
805 * know how big the buttons are).
807 va_start(ap, listid);
810 char *btext = va_arg(ap, char *);
813 bid = va_arg(ap, int);
814 r.left = rpos; r.top = y;
815 r.right = rwid; r.bottom = PUSHBTNHEIGHT;
816 y += r.bottom + GAPWITHIN;
817 doctl(cp, r, "BUTTON",
818 WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
823 /* Compute list box height. LISTDEFHEIGHT, or height of buttons. */
826 if (y < LISTDEFHEIGHT) y = LISTDEFHEIGHT;
827 r.left = GAPBETWEEN; r.top = cp->ypos;
828 r.right = lwid; r.bottom = y;
829 cp->ypos += y + GAPBETWEEN;
830 doctl(cp, r, "LISTBOX",
831 WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL | LBS_HASSTRINGS,
837 * Another special control: the environment-variable setter. A
838 * static line first; then a pair of edit boxes with associated
839 * statics, and two buttons; then a list box.
841 void envsetter(struct ctlpos *cp, char *stext, int sid,
842 char *e1stext, int e1sid, int e1id,
843 char *e2stext, int e2sid, int e2id,
844 int listid, char *b1text, int b1id, char *b2text, int b2id) {
846 const int height = (STATICHEIGHT > EDITHEIGHT && STATICHEIGHT > PUSHBTNHEIGHT ?
848 EDITHEIGHT > PUSHBTNHEIGHT ?
849 EDITHEIGHT : PUSHBTNHEIGHT);
850 const static int percents[] = { 20, 35, 10, 25 };
851 int i, j, xpos, percent;
852 const int LISTHEIGHT = 42;
854 /* The static control. */
855 r.left = GAPBETWEEN; r.top = cp->ypos;
856 r.right = cp->width; r.bottom = STATICHEIGHT;
857 cp->ypos += r.bottom + GAPWITHIN;
858 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
860 /* The statics+edits+buttons. */
861 for (j = 0; j < 2; j++) {
863 for (i = 0; i < 4; i++) {
864 xpos = (cp->width + GAPBETWEEN) * percent / 100;
865 r.left = xpos + GAPBETWEEN;
866 percent += percents[i];
867 xpos = (cp->width + GAPBETWEEN) * percent / 100;
868 r.right = xpos - r.left;
870 r.bottom = (i==0 ? STATICHEIGHT :
873 r.top += (height-r.bottom)/2;
875 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0,
876 j==0 ? e1stext : e2stext, j==0 ? e1sid : e2sid);
879 WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
881 "", j==0 ? e1id : e2id);
883 doctl(cp, r, "BUTTON",
884 WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
886 j==0 ? b1text : b2text, j==0 ? b1id : b2id);
889 cp->ypos += height + GAPWITHIN;
893 r.left = GAPBETWEEN; r.top = cp->ypos;
894 r.right = cp->width; r.bottom = LISTHEIGHT;
895 cp->ypos += r.bottom + GAPBETWEEN;
896 doctl(cp, r, "LISTBOX",
897 WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL | LBS_HASSTRINGS |
904 * Yet another special control: the character-class setter. A
905 * static, then a list, then a line containing a
906 * button-and-static-and-edit.
908 void charclass(struct ctlpos *cp, char *stext, int sid, int listid,
909 char *btext, int bid, int eid, char *s2text, int s2id) {
911 const int height = (STATICHEIGHT > EDITHEIGHT && STATICHEIGHT > PUSHBTNHEIGHT ?
913 EDITHEIGHT > PUSHBTNHEIGHT ?
914 EDITHEIGHT : PUSHBTNHEIGHT);
915 const static int percents[] = { 30, 40, 30 };
916 int i, xpos, percent;
917 const int LISTHEIGHT = 66;
919 /* The static control. */
920 r.left = GAPBETWEEN; r.top = cp->ypos;
921 r.right = cp->width; r.bottom = STATICHEIGHT;
922 cp->ypos += r.bottom + GAPWITHIN;
923 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
926 r.left = GAPBETWEEN; r.top = cp->ypos;
927 r.right = cp->width; r.bottom = LISTHEIGHT;
928 cp->ypos += r.bottom + GAPWITHIN;
929 doctl(cp, r, "LISTBOX",
930 WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL | LBS_HASSTRINGS |
935 /* The button+static+edit. */
937 for (i = 0; i < 3; i++) {
938 r.left = xpos + GAPBETWEEN;
939 percent += percents[i];
940 xpos = (cp->width + GAPBETWEEN) * percent / 100;
941 r.right = xpos - r.left;
943 r.bottom = (i==0 ? PUSHBTNHEIGHT :
944 i==1 ? STATICHEIGHT :
946 r.top += (height-r.bottom)/2;
948 doctl(cp, r, "BUTTON",
949 WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
952 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE | SS_CENTER,
956 WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL,
957 WS_EX_CLIENTEDGE, "", eid);
960 cp->ypos += height + GAPBETWEEN;
964 * A special control (horrors!). The colour editor. A static line;
965 * then on the left, a list box, and on the right, a sequence of
966 * two-part statics followed by a button.
968 void colouredit(struct ctlpos *cp, char *stext, int sid, int listid,
969 char *btext, int bid, ...) {
973 int lwid, rwid, rpos;
974 const int LISTHEIGHT = 66;
976 /* The static control. */
977 r.left = GAPBETWEEN; r.top = cp->ypos;
978 r.right = cp->width; r.bottom = STATICHEIGHT;
979 cp->ypos += r.bottom + GAPWITHIN;
980 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
982 rpos = GAPBETWEEN + 2 * (cp->width + GAPBETWEEN) / 3;
983 lwid = rpos - 2*GAPBETWEEN;
984 rwid = cp->width + GAPBETWEEN - rpos;
987 r.left = GAPBETWEEN; r.top = cp->ypos;
988 r.right = lwid; r.bottom = LISTHEIGHT;
989 doctl(cp, r, "LISTBOX",
990 WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL | LBS_HASSTRINGS |
1001 ltext = va_arg(ap, char *);
1003 lid = va_arg(ap, int);
1004 rid = va_arg(ap, int);
1005 r.top = y; r.bottom = STATICHEIGHT;
1006 y += r.bottom + GAPWITHIN;
1007 r.left = rpos; r.right = rwid/2;
1008 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, ltext, lid);
1009 r.left = rpos + r.right; r.right = rwid - r.right;
1010 doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE | SS_RIGHT, 0, "", rid);
1015 r.top = y + 2*GAPWITHIN; r.bottom = PUSHBTNHEIGHT;
1016 r.left = rpos; r.right = rwid;
1017 doctl(cp, r, "BUTTON",
1018 WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
1021 cp->ypos += LISTHEIGHT + GAPBETWEEN;
1024 static int GeneralPanelProc (HWND hwnd, UINT msg,
1025 WPARAM wParam, LPARAM lParam) {
1029 HFONT hfont = (HFONT)wParam;
1036 oldfont = SelectObject(hdc, hfont);
1037 GetTextMetrics(hdc, &tm);
1038 units = (tm.tmHeight << 16) | tm.tmAveCharWidth;
1039 SelectObject(hdc, oldfont);
1041 SetWindowLong(hwnd, GWL_USERDATA, units);
1042 SetWindowLong(hwnd, DWL_USER, wParam);
1046 SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
1049 DestroyWindow (hwnd);
1055 static char savedsession[2048];
1057 static int CALLBACK ConnectionProc (HWND hwnd, UINT msg,
1058 WPARAM wParam, LPARAM lParam) {
1064 /* Accelerators used: [aco] dehlnprstwx */
1065 ctlposinit(&cp, hwnd);
1067 "Host &Name", IDC0_HOSTSTATIC, IDC0_HOST, 75,
1068 "&Port", IDC0_PORTSTATIC, IDC0_PORT, 25, NULL);
1069 radioline(&cp, "Protocol:", IDC0_PROTSTATIC, 3,
1070 "&Raw", IDC0_PROTRAW,
1071 "&Telnet", IDC0_PROTTELNET,
1077 IDC0_PROTSSH, NULL);
1078 sesssaver(&cp, "Stor&ed Sessions",
1079 IDC0_SESSSTATIC, IDC0_SESSEDIT, IDC0_SESSLIST,
1080 "&Load", IDC0_SESSLOAD,
1081 "&Save", IDC0_SESSSAVE,
1082 "&Delete", IDC0_SESSDEL, NULL);
1083 checkbox(&cp, "Close Window on E&xit", IDC0_CLOSEEXIT);
1084 checkbox(&cp, "&Warn on Close", IDC0_CLOSEWARN);
1086 SetDlgItemText (hwnd, IDC0_HOST, cfg.host);
1087 SetDlgItemText (hwnd, IDC0_SESSEDIT, savedsession);
1088 SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE);
1089 for (i = 0; i < nsessions; i++)
1090 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING,
1091 0, (LPARAM) (sessions[i]));
1092 CheckRadioButton (hwnd, IDC0_PROTRAW, IDC0_PROTSSH,
1093 cfg.protocol==PROT_SSH ? IDC0_PROTSSH :
1094 cfg.protocol==PROT_TELNET ? IDC0_PROTTELNET : IDC0_PROTRAW );
1095 CheckDlgButton (hwnd, IDC0_CLOSEEXIT, cfg.close_on_exit);
1096 CheckDlgButton (hwnd, IDC0_CLOSEWARN, cfg.warn_on_close);
1100 * Button release should trigger WM_OK if there was a
1101 * previous double click on the session list.
1105 SendMessage (GetParent(hwnd), WM_COMMAND, IDOK, 0);
1108 switch (LOWORD(wParam)) {
1109 case IDC0_PROTTELNET:
1112 if (HIWORD(wParam) == BN_CLICKED ||
1113 HIWORD(wParam) == BN_DOUBLECLICKED) {
1114 int i = IsDlgButtonChecked (hwnd, IDC0_PROTSSH);
1115 int j = IsDlgButtonChecked (hwnd, IDC0_PROTTELNET);
1116 cfg.protocol = i ? PROT_SSH : j ? PROT_TELNET : PROT_RAW ;
1117 if ((cfg.protocol == PROT_SSH && cfg.port == 23) ||
1118 (cfg.protocol == PROT_TELNET && cfg.port == 22)) {
1119 cfg.port = i ? 22 : 23;
1120 SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE);
1125 if (HIWORD(wParam) == EN_CHANGE)
1126 GetDlgItemText (hwnd, IDC0_HOST, cfg.host,
1127 sizeof(cfg.host)-1);
1130 if (HIWORD(wParam) == EN_CHANGE)
1131 MyGetDlgItemInt (hwnd, IDC0_PORT, &cfg.port);
1133 case IDC0_CLOSEEXIT:
1134 if (HIWORD(wParam) == BN_CLICKED ||
1135 HIWORD(wParam) == BN_DOUBLECLICKED)
1136 cfg.close_on_exit = IsDlgButtonChecked (hwnd, IDC0_CLOSEEXIT);
1138 case IDC0_CLOSEWARN:
1139 if (HIWORD(wParam) == BN_CLICKED ||
1140 HIWORD(wParam) == BN_DOUBLECLICKED)
1141 cfg.warn_on_close = IsDlgButtonChecked (hwnd, IDC0_CLOSEWARN);
1144 if (HIWORD(wParam) == EN_CHANGE) {
1145 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
1147 GetDlgItemText (hwnd, IDC0_SESSEDIT,
1148 savedsession, sizeof(savedsession)-1);
1149 savedsession[sizeof(savedsession)-1] = '\0';
1153 if (HIWORD(wParam) == BN_CLICKED ||
1154 HIWORD(wParam) == BN_DOUBLECLICKED) {
1159 GetDlgItemText (hwnd, IDC0_SESSEDIT, str, sizeof(str)-1);
1161 int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
1162 LB_GETCURSEL, 0, 0);
1167 strcpy (str, sessions[n]);
1169 save_settings (str, !!strcmp(str, "Default Settings"));
1170 get_sesslist (FALSE);
1171 get_sesslist (TRUE);
1172 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_RESETCONTENT,
1174 for (i = 0; i < nsessions; i++)
1175 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING,
1176 0, (LPARAM) (sessions[i]));
1177 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
1183 if (LOWORD(wParam) == IDC0_SESSLOAD &&
1184 HIWORD(wParam) != BN_CLICKED &&
1185 HIWORD(wParam) != BN_DOUBLECLICKED)
1187 if (LOWORD(wParam) == IDC0_SESSLIST &&
1188 HIWORD(wParam) != LBN_DBLCLK)
1191 int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
1192 LB_GETCURSEL, 0, 0);
1197 load_settings (sessions[n],
1198 !!strcmp(sessions[n], "Default Settings"));
1199 SetDlgItemText (hwnd, IDC0_HOST, cfg.host);
1200 SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE);
1201 CheckRadioButton (hwnd, IDC0_PROTRAW, IDC0_PROTSSH,
1202 (cfg.protocol==PROT_SSH ? IDC0_PROTSSH :
1203 cfg.protocol==PROT_TELNET ? IDC0_PROTTELNET : IDC0_PROTRAW));
1204 CheckDlgButton (hwnd, IDC0_CLOSEEXIT, cfg.close_on_exit);
1205 CheckDlgButton (hwnd, IDC0_CLOSEWARN, cfg.warn_on_close);
1206 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
1209 if (LOWORD(wParam) == IDC0_SESSLIST) {
1211 * A double-click on a saved session should
1212 * actually start the session, not just load it.
1213 * Unless it's Default Settings or some other
1214 * host-less set of saved settings.
1223 if (HIWORD(wParam) == BN_CLICKED ||
1224 HIWORD(wParam) == BN_DOUBLECLICKED) {
1225 int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
1226 LB_GETCURSEL, 0, 0);
1227 if (n == LB_ERR || n == 0) {
1231 del_settings(sessions[n]);
1232 get_sesslist (FALSE);
1233 get_sesslist (TRUE);
1234 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_RESETCONTENT,
1236 for (i = 0; i < nsessions; i++)
1237 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING,
1238 0, (LPARAM) (sessions[i]));
1239 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
1244 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1247 static int CALLBACK KeyboardProc (HWND hwnd, UINT msg,
1248 WPARAM wParam, LPARAM lParam) {
1252 /* Accelerators used: [aco] 4?ehiklmnprsuvxy */
1253 ctlposinit(&cp, hwnd);
1254 radioline(&cp, "Action of Backspace:", IDC1_DELSTATIC, 2,
1255 "Control-&H", IDC1_DEL008,
1256 "Control-&? (127)", IDC1_DEL127, NULL);
1257 radioline(&cp, "Action of Home and End:", IDC1_HOMESTATIC, 2,
1258 "&Standard", IDC1_HOMETILDE,
1259 "&rxvt", IDC1_HOMERXVT, NULL);
1260 radioline(&cp, "Function key and keypad layout:", IDC1_FUNCSTATIC, 3,
1261 "&VT400", IDC1_FUNCTILDE,
1262 "&Linux", IDC1_FUNCLINUX,
1263 "&Xterm R6", IDC1_FUNCXTERM, NULL);
1264 radioline(&cp, "Initial state of cursor keys:", IDC1_CURSTATIC, 2,
1265 "&Normal", IDC1_CURNORMAL,
1266 "A&pplication", IDC1_CURAPPLIC, NULL);
1267 radioline(&cp, "Initial state of numeric keypad:", IDC1_KPSTATIC, 3,
1268 "Nor&mal", IDC1_KPNORMAL,
1269 "Appl&ication", IDC1_KPAPPLIC,
1270 "N&etHack", IDC1_KPNH, NULL);
1271 checkbox(&cp, "ALT-F&4 is special (closes window)", IDC1_ALTF4);
1272 checkbox(&cp, "ALT-Space is special (S&ystem menu)", IDC1_ALTSPACE);
1273 checkbox(&cp, "&Use local terminal line discipline", IDC1_LDISCTERM);
1274 checkbox(&cp, "Reset scrollback on &keypress", IDC1_SCROLLKEY);
1276 CheckRadioButton (hwnd, IDC1_DEL008, IDC1_DEL127,
1277 cfg.bksp_is_delete ? IDC1_DEL127 : IDC1_DEL008);
1278 CheckRadioButton (hwnd, IDC1_HOMETILDE, IDC1_HOMERXVT,
1279 cfg.rxvt_homeend ? IDC1_HOMERXVT : IDC1_HOMETILDE);
1280 CheckRadioButton (hwnd, IDC1_FUNCTILDE, IDC1_FUNCXTERM,
1282 (cfg.funky_type==2 ? IDC1_FUNCXTERM
1285 CheckRadioButton (hwnd, IDC1_CURNORMAL, IDC1_CURAPPLIC,
1286 cfg.app_cursor ? IDC1_CURAPPLIC : IDC1_CURNORMAL);
1287 CheckRadioButton (hwnd, IDC1_KPNORMAL, IDC1_KPNH,
1288 cfg.nethack_keypad ? IDC1_KPNH :
1289 cfg.app_keypad ? IDC1_KPAPPLIC : IDC1_KPNORMAL);
1290 CheckDlgButton (hwnd, IDC1_ALTF4, cfg.alt_f4);
1291 CheckDlgButton (hwnd, IDC1_ALTSPACE, cfg.alt_space);
1292 CheckDlgButton (hwnd, IDC1_LDISCTERM, cfg.ldisc_term);
1293 CheckDlgButton (hwnd, IDC1_SCROLLKEY, cfg.scroll_on_key);
1296 if (HIWORD(wParam) == BN_CLICKED ||
1297 HIWORD(wParam) == BN_DOUBLECLICKED)
1298 switch (LOWORD(wParam)) {
1301 cfg.bksp_is_delete = IsDlgButtonChecked (hwnd, IDC1_DEL127);
1303 case IDC1_HOMETILDE:
1305 cfg.rxvt_homeend = IsDlgButtonChecked (hwnd, IDC1_HOMERXVT);
1307 case IDC1_FUNCXTERM:
1310 case IDC1_FUNCTILDE:
1311 case IDC1_FUNCLINUX:
1312 cfg.funky_type = IsDlgButtonChecked (hwnd, IDC1_FUNCLINUX);
1316 cfg.app_keypad = IsDlgButtonChecked (hwnd, IDC1_KPAPPLIC);
1317 cfg.nethack_keypad = FALSE;
1320 cfg.app_keypad = FALSE;
1321 cfg.nethack_keypad = TRUE;
1323 case IDC1_CURNORMAL:
1324 case IDC1_CURAPPLIC:
1325 cfg.app_cursor = IsDlgButtonChecked (hwnd, IDC1_CURAPPLIC);
1328 if (HIWORD(wParam) == BN_CLICKED ||
1329 HIWORD(wParam) == BN_DOUBLECLICKED)
1330 cfg.alt_f4 = IsDlgButtonChecked (hwnd, IDC1_ALTF4);
1333 if (HIWORD(wParam) == BN_CLICKED ||
1334 HIWORD(wParam) == BN_DOUBLECLICKED)
1335 cfg.alt_space = IsDlgButtonChecked (hwnd, IDC1_ALTSPACE);
1337 case IDC1_LDISCTERM:
1338 if (HIWORD(wParam) == BN_CLICKED ||
1339 HIWORD(wParam) == BN_DOUBLECLICKED)
1340 cfg.ldisc_term = IsDlgButtonChecked (hwnd, IDC1_LDISCTERM);
1342 case IDC1_SCROLLKEY:
1343 if (HIWORD(wParam) == BN_CLICKED ||
1344 HIWORD(wParam) == BN_DOUBLECLICKED)
1345 cfg.scroll_on_key = IsDlgButtonChecked (hwnd, IDC1_SCROLLKEY);
1349 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1352 static void fmtfont (char *buf) {
1353 sprintf (buf, "Font: %s, ", cfg.font);
1355 strcat(buf, "bold, ");
1356 if (cfg.fontheight == 0)
1357 strcat (buf, "default height");
1359 sprintf (buf+strlen(buf), "%d-%s",
1360 (cfg.fontheight < 0 ? -cfg.fontheight : cfg.fontheight),
1361 (cfg.fontheight < 0 ? "pixel" : "point"));
1364 static int CALLBACK TerminalProc (HWND hwnd, UINT msg,
1365 WPARAM wParam, LPARAM lParam) {
1369 char fontstatic[256];
1373 /* Accelerators used: [aco] dghlmnprsw */
1374 ctlposinit(&cp, hwnd);
1376 "&Rows", IDC2_ROWSSTATIC, IDC2_ROWSEDIT, 33,
1377 "Colu&mns", IDC2_COLSSTATIC, IDC2_COLSEDIT, 33,
1378 "&Scrollback", IDC2_SAVESTATIC, IDC2_SAVEEDIT, 33,
1380 staticbtn(&cp, "", IDC2_FONTSTATIC, "C&hange...", IDC2_CHOOSEFONT);
1381 checkbox(&cp, "Auto &wrap mode initially on", IDC2_WRAPMODE);
1382 checkbox(&cp, "&DEC Origin Mode initially on", IDC2_DECOM);
1383 checkbox(&cp, "Implicit CR in every &LF", IDC2_LFHASCR);
1384 checkbox(&cp, "Bee&p enabled", IDC1_BEEP);
1385 checkbox(&cp, "Use Back&ground colour erase", IDC2_BCE);
1386 checkbox(&cp, "Enable bli&nking text", IDC2_BLINKTEXT);
1388 CheckDlgButton (hwnd, IDC2_WRAPMODE, cfg.wrap_mode);
1389 CheckDlgButton (hwnd, IDC2_DECOM, cfg.dec_om);
1390 CheckDlgButton (hwnd, IDC2_LFHASCR, cfg.lfhascr);
1391 SetDlgItemInt (hwnd, IDC2_ROWSEDIT, cfg.height, FALSE);
1392 SetDlgItemInt (hwnd, IDC2_COLSEDIT, cfg.width, FALSE);
1393 SetDlgItemInt (hwnd, IDC2_SAVEEDIT, cfg.savelines, FALSE);
1394 fmtfont (fontstatic);
1395 SetDlgItemText (hwnd, IDC2_FONTSTATIC, fontstatic);
1396 CheckDlgButton (hwnd, IDC1_BEEP, cfg.beep);
1397 CheckDlgButton (hwnd, IDC2_BCE, cfg.bce);
1398 CheckDlgButton (hwnd, IDC2_BLINKTEXT, cfg.blinktext);
1401 switch (LOWORD(wParam)) {
1403 if (HIWORD(wParam) == BN_CLICKED ||
1404 HIWORD(wParam) == BN_DOUBLECLICKED)
1405 cfg.wrap_mode = IsDlgButtonChecked (hwnd, IDC2_WRAPMODE);
1408 if (HIWORD(wParam) == BN_CLICKED ||
1409 HIWORD(wParam) == BN_DOUBLECLICKED)
1410 cfg.dec_om = IsDlgButtonChecked (hwnd, IDC2_DECOM);
1413 if (HIWORD(wParam) == BN_CLICKED ||
1414 HIWORD(wParam) == BN_DOUBLECLICKED)
1415 cfg.lfhascr = IsDlgButtonChecked (hwnd, IDC2_LFHASCR);
1418 if (HIWORD(wParam) == EN_CHANGE)
1419 MyGetDlgItemInt (hwnd, IDC2_ROWSEDIT, &cfg.height);
1422 if (HIWORD(wParam) == EN_CHANGE)
1423 MyGetDlgItemInt (hwnd, IDC2_COLSEDIT, &cfg.width);
1426 if (HIWORD(wParam) == EN_CHANGE)
1427 MyGetDlgItemInt (hwnd, IDC2_SAVEEDIT, &cfg.savelines);
1429 case IDC2_CHOOSEFONT:
1430 lf.lfHeight = cfg.fontheight;
1431 lf.lfWidth = lf.lfEscapement = lf.lfOrientation = 0;
1432 lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = 0;
1433 lf.lfWeight = (cfg.fontisbold ? FW_BOLD : 0);
1434 lf.lfCharSet = cfg.fontcharset;
1435 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
1436 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1437 lf.lfQuality = DEFAULT_QUALITY;
1438 lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
1439 strncpy (lf.lfFaceName, cfg.font, sizeof(lf.lfFaceName)-1);
1440 lf.lfFaceName[sizeof(lf.lfFaceName)-1] = '\0';
1442 cf.lStructSize = sizeof(cf);
1443 cf.hwndOwner = hwnd;
1445 cf.Flags = CF_FIXEDPITCHONLY | CF_FORCEFONTEXIST |
1446 CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
1448 if (ChooseFont (&cf)) {
1449 strncpy (cfg.font, lf.lfFaceName, sizeof(cfg.font)-1);
1450 cfg.font[sizeof(cfg.font)-1] = '\0';
1451 cfg.fontisbold = (lf.lfWeight == FW_BOLD);
1452 cfg.fontcharset = lf.lfCharSet;
1453 cfg.fontheight = lf.lfHeight;
1454 fmtfont (fontstatic);
1455 SetDlgItemText (hwnd, IDC2_FONTSTATIC, fontstatic);
1459 if (HIWORD(wParam) == BN_CLICKED ||
1460 HIWORD(wParam) == BN_DOUBLECLICKED)
1461 cfg.beep = IsDlgButtonChecked (hwnd, IDC1_BEEP);
1463 case IDC2_BLINKTEXT:
1464 if (HIWORD(wParam) == BN_CLICKED ||
1465 HIWORD(wParam) == BN_DOUBLECLICKED)
1466 cfg.blinktext = IsDlgButtonChecked (hwnd, IDC2_BLINKTEXT);
1469 if (HIWORD(wParam) == BN_CLICKED ||
1470 HIWORD(wParam) == BN_DOUBLECLICKED)
1471 cfg.bce = IsDlgButtonChecked (hwnd, IDC2_BCE);
1476 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1479 static int CALLBACK WindowProc (HWND hwnd, UINT msg,
1480 WPARAM wParam, LPARAM lParam) {
1484 /* Accelerators used: [aco] bikty */
1485 ctlposinit(&cp, hwnd);
1487 "Initial window &title:", IDCW_WINTITLE, IDCW_WINEDIT, 100,
1489 checkbox(&cp, "Avoid ever using &icon title", IDCW_WINNAME);
1490 checkbox(&cp, "&Blinking cursor", IDCW_BLINKCUR);
1491 checkbox(&cp, "Displa&y scrollbar", IDCW_SCROLLBAR);
1492 checkbox(&cp, "Loc&k Window size", IDCW_LOCKSIZE);
1494 SetDlgItemText (hwnd, IDCW_WINEDIT, cfg.wintitle);
1495 CheckDlgButton (hwnd, IDCW_WINNAME, cfg.win_name_always);
1496 CheckDlgButton (hwnd, IDCW_BLINKCUR, cfg.blink_cur);
1497 CheckDlgButton (hwnd, IDCW_SCROLLBAR, cfg.scrollbar);
1498 CheckDlgButton (hwnd, IDCW_LOCKSIZE, cfg.locksize);
1501 switch (LOWORD(wParam)) {
1503 if (HIWORD(wParam) == BN_CLICKED ||
1504 HIWORD(wParam) == BN_DOUBLECLICKED)
1505 cfg.win_name_always = IsDlgButtonChecked (hwnd, IDCW_WINNAME);
1508 if (HIWORD(wParam) == BN_CLICKED ||
1509 HIWORD(wParam) == BN_DOUBLECLICKED)
1510 cfg.blink_cur = IsDlgButtonChecked (hwnd, IDCW_BLINKCUR);
1512 case IDCW_SCROLLBAR:
1513 if (HIWORD(wParam) == BN_CLICKED ||
1514 HIWORD(wParam) == BN_DOUBLECLICKED)
1515 cfg.scrollbar = IsDlgButtonChecked (hwnd, IDCW_SCROLLBAR);
1518 if (HIWORD(wParam) == BN_CLICKED ||
1519 HIWORD(wParam) == BN_DOUBLECLICKED)
1520 cfg.locksize = IsDlgButtonChecked (hwnd, IDCW_LOCKSIZE);
1523 if (HIWORD(wParam) == EN_CHANGE)
1524 GetDlgItemText (hwnd, IDCW_WINEDIT, cfg.wintitle,
1525 sizeof(cfg.wintitle)-1);
1530 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1533 static int CALLBACK TelnetProc (HWND hwnd, UINT msg,
1534 WPARAM wParam, LPARAM lParam) {
1540 /* Accelerators used: [aco] bdflrstuv */
1541 ctlposinit(&cp, hwnd);
1542 staticedit(&cp, "Terminal-&type string", IDC3_TTSTATIC, IDC3_TTEDIT);
1543 staticedit(&cp, "Terminal-&speed string", IDC3_TSSTATIC, IDC3_TSEDIT);
1544 staticedit(&cp, "Auto-login &username", IDC3_LOGSTATIC, IDC3_LOGEDIT);
1545 envsetter(&cp, "Environment variables:", IDC3_ENVSTATIC,
1546 "&Variable", IDC3_VARSTATIC, IDC3_VAREDIT,
1547 "Va&lue", IDC3_VALSTATIC, IDC3_VALEDIT,
1549 "A&dd", IDC3_ENVADD, "&Remove", IDC3_ENVREMOVE);
1550 radioline(&cp, "Handling of OLD_ENVIRON ambiguity:", IDC3_EMSTATIC, 2,
1551 "&BSD (commonplace)", IDC3_EMBSD,
1552 "R&FC 1408 (unusual)", IDC3_EMRFC, NULL);
1554 SetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype);
1555 SetDlgItemText (hwnd, IDC3_TSEDIT, cfg.termspeed);
1556 SetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username);
1558 char *p = cfg.environmt;
1560 SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_ADDSTRING, 0,
1565 CheckRadioButton (hwnd, IDC3_EMBSD, IDC3_EMRFC,
1566 cfg.rfc_environ ? IDC3_EMRFC : IDC3_EMBSD);
1569 switch (LOWORD(wParam)) {
1571 if (HIWORD(wParam) == EN_CHANGE)
1572 GetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype,
1573 sizeof(cfg.termtype)-1);
1576 if (HIWORD(wParam) == EN_CHANGE)
1577 GetDlgItemText (hwnd, IDC3_TSEDIT, cfg.termspeed,
1578 sizeof(cfg.termspeed)-1);
1581 if (HIWORD(wParam) == EN_CHANGE)
1582 GetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username,
1583 sizeof(cfg.username)-1);
1587 cfg.rfc_environ = IsDlgButtonChecked (hwnd, IDC3_EMRFC);
1590 if (HIWORD(wParam) == BN_CLICKED ||
1591 HIWORD(wParam) == BN_DOUBLECLICKED) {
1592 char str[sizeof(cfg.environmt)];
1594 GetDlgItemText (hwnd, IDC3_VAREDIT, str, sizeof(str)-1);
1599 p = str + strlen(str);
1601 GetDlgItemText (hwnd, IDC3_VALEDIT, p, sizeof(str)-1-(p-str));
1611 if ((p-cfg.environmt) + strlen(str) + 2 < sizeof(cfg.environmt)) {
1613 p[strlen(str)+1] = '\0';
1614 SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_ADDSTRING,
1616 SetDlgItemText (hwnd, IDC3_VAREDIT, "");
1617 SetDlgItemText (hwnd, IDC3_VALEDIT, "");
1619 MessageBox(hwnd, "Environment too big", "PuTTY Error",
1620 MB_OK | MB_ICONERROR);
1624 case IDC3_ENVREMOVE:
1625 if (HIWORD(wParam) != BN_CLICKED &&
1626 HIWORD(wParam) != BN_DOUBLECLICKED)
1628 i = SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_GETCURSEL, 0, 0);
1634 SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_DELETESTRING,
1661 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1664 static int CALLBACK SshProc (HWND hwnd, UINT msg,
1665 WPARAM wParam, LPARAM lParam) {
1668 char filename[sizeof(cfg.keyfile)];
1672 /* Accelerators used: [aco] 123abdkmprtuw */
1673 ctlposinit(&cp, hwnd);
1674 staticedit(&cp, "Terminal-&type string", IDC3_TTSTATIC, IDC3_TTEDIT);
1675 staticedit(&cp, "Auto-login &username", IDC3_LOGSTATIC, IDC3_LOGEDIT);
1677 "&Remote command:", IDC3_CMDSTATIC, IDC3_CMDEDIT, 100,
1679 checkbox(&cp, "Don't allocate a &pseudo-terminal", IDC3_NOPTY);
1680 checkbox(&cp, "Atte&mpt TIS or CryptoCard authentication",
1682 checkbox(&cp, "Allow &agent forwarding", IDC3_AGENTFWD);
1683 editbutton(&cp, "Private &key file for authentication:",
1684 IDC3_PKSTATIC, IDC3_PKEDIT, "Bro&wse...", IDC3_PKBUTTON);
1685 radioline(&cp, "Preferred SSH protocol version:",
1686 IDC3_SSHPROTSTATIC, 2,
1687 "&1", IDC3_SSHPROT1, "&2", IDC3_SSHPROT2, NULL);
1688 radioline(&cp, "Preferred encryption algorithm:", IDC3_CIPHERSTATIC, 3,
1689 "&3DES", IDC3_CIPHER3DES,
1690 "&Blowfish", IDC3_CIPHERBLOWF,
1691 "&DES", IDC3_CIPHERDES, NULL);
1693 SetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype);
1694 SetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username);
1695 CheckDlgButton (hwnd, IDC3_NOPTY, cfg.nopty);
1696 CheckDlgButton (hwnd, IDC3_AGENTFWD, cfg.agentfwd);
1697 CheckRadioButton (hwnd, IDC3_CIPHER3DES, IDC3_CIPHERDES,
1698 cfg.cipher == CIPHER_BLOWFISH ? IDC3_CIPHERBLOWF :
1699 cfg.cipher == CIPHER_DES ? IDC3_CIPHERDES :
1701 CheckRadioButton (hwnd, IDC3_SSHPROT1, IDC3_SSHPROT2,
1702 cfg.sshprot == 1 ? IDC3_SSHPROT1 : IDC3_SSHPROT2);
1703 CheckDlgButton (hwnd, IDC3_AUTHTIS, cfg.try_tis_auth);
1704 SetDlgItemText (hwnd, IDC3_PKEDIT, cfg.keyfile);
1705 SetDlgItemText (hwnd, IDC3_CMDEDIT, cfg.remote_cmd);
1708 switch (LOWORD(wParam)) {
1710 if (HIWORD(wParam) == EN_CHANGE)
1711 GetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype,
1712 sizeof(cfg.termtype)-1);
1715 if (HIWORD(wParam) == EN_CHANGE)
1716 GetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username,
1717 sizeof(cfg.username)-1);
1720 if (HIWORD(wParam) == BN_CLICKED ||
1721 HIWORD(wParam) == BN_DOUBLECLICKED)
1722 cfg.nopty = IsDlgButtonChecked (hwnd, IDC3_NOPTY);
1725 if (HIWORD(wParam) == BN_CLICKED ||
1726 HIWORD(wParam) == BN_DOUBLECLICKED)
1727 cfg.agentfwd = IsDlgButtonChecked (hwnd, IDC3_AGENTFWD);
1729 case IDC3_CIPHER3DES:
1730 case IDC3_CIPHERBLOWF:
1731 case IDC3_CIPHERDES:
1732 if (HIWORD(wParam) == BN_CLICKED ||
1733 HIWORD(wParam) == BN_DOUBLECLICKED) {
1734 if (IsDlgButtonChecked (hwnd, IDC3_CIPHER3DES))
1735 cfg.cipher = CIPHER_3DES;
1736 else if (IsDlgButtonChecked (hwnd, IDC3_CIPHERBLOWF))
1737 cfg.cipher = CIPHER_BLOWFISH;
1738 else if (IsDlgButtonChecked (hwnd, IDC3_CIPHERDES))
1739 cfg.cipher = CIPHER_DES;
1744 if (HIWORD(wParam) == BN_CLICKED ||
1745 HIWORD(wParam) == BN_DOUBLECLICKED) {
1746 if (IsDlgButtonChecked (hwnd, IDC3_SSHPROT1))
1748 else if (IsDlgButtonChecked (hwnd, IDC3_SSHPROT2))
1753 if (HIWORD(wParam) == BN_CLICKED ||
1754 HIWORD(wParam) == BN_DOUBLECLICKED)
1755 cfg.try_tis_auth = IsDlgButtonChecked (hwnd, IDC3_AUTHTIS);
1758 if (HIWORD(wParam) == EN_CHANGE)
1759 GetDlgItemText (hwnd, IDC3_PKEDIT, cfg.keyfile,
1760 sizeof(cfg.keyfile)-1);
1763 if (HIWORD(wParam) == EN_CHANGE)
1764 GetDlgItemText (hwnd, IDC3_CMDEDIT, cfg.remote_cmd,
1765 sizeof(cfg.remote_cmd)-1);
1769 * FIXME: this crashes. Find out why.
1771 memset(&of, 0, sizeof(of));
1772 #ifdef OPENFILENAME_SIZE_VERSION_400
1773 of.lStructSize = OPENFILENAME_SIZE_VERSION_400;
1775 of.lStructSize = sizeof(of);
1777 of.hwndOwner = hwnd;
1778 of.lpstrFilter = "All Files\0*\0\0\0";
1779 of.lpstrCustomFilter = NULL;
1780 of.nFilterIndex = 1;
1781 of.lpstrFile = filename; strcpy(filename, cfg.keyfile);
1782 of.nMaxFile = sizeof(filename);
1783 of.lpstrFileTitle = NULL;
1784 of.lpstrInitialDir = NULL;
1785 of.lpstrTitle = "Select Public Key File";
1787 if (GetOpenFileName(&of)) {
1788 strcpy(cfg.keyfile, filename);
1789 SetDlgItemText (hwnd, IDC3_PKEDIT, cfg.keyfile);
1795 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1798 static int CALLBACK SelectionProc (HWND hwnd, UINT msg,
1799 WPARAM wParam, LPARAM lParam) {
1805 /* Accelerators used: [aco] stwx */
1806 ctlposinit(&cp, hwnd);
1807 radiobig(&cp, "Action of mouse buttons:", IDC4_MBSTATIC,
1808 "&Windows (Right pastes, Middle extends)", IDC4_MBWINDOWS,
1809 "&xterm (Right extends, Middle pastes)", IDC4_MBXTERM,
1811 charclass(&cp, "Character classes:", IDC4_CCSTATIC, IDC4_CCLIST,
1812 "&Set", IDC4_CCSET, IDC4_CCEDIT,
1813 "&to class", IDC4_CCSTATIC2);
1815 CheckRadioButton (hwnd, IDC4_MBWINDOWS, IDC4_MBXTERM,
1816 cfg.mouse_is_xterm ? IDC4_MBXTERM : IDC4_MBWINDOWS);
1818 static int tabs[4] = {25, 61, 96, 128};
1819 SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_SETTABSTOPS, 4,
1822 for (i=0; i<256; i++) {
1824 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
1825 (i>=0x21 && i != 0x7F) ? i : ' ',
1827 SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_ADDSTRING, 0,
1832 switch (LOWORD(wParam)) {
1833 case IDC4_MBWINDOWS:
1835 cfg.mouse_is_xterm = IsDlgButtonChecked (hwnd, IDC4_MBXTERM);
1841 int n = GetDlgItemInt (hwnd, IDC4_CCEDIT, &ok, FALSE);
1846 for (i=0; i<256; i++)
1847 if (SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_GETSEL,
1850 cfg.wordness[i] = n;
1851 SendDlgItemMessage (hwnd, IDC4_CCLIST,
1852 LB_DELETESTRING, i, 0);
1853 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
1854 (i>=0x21 && i != 0x7F) ? i : ' ',
1856 SendDlgItemMessage (hwnd, IDC4_CCLIST,
1866 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1869 static int CALLBACK ColourProc (HWND hwnd, UINT msg,
1870 WPARAM wParam, LPARAM lParam) {
1871 static const char *const colours[] = {
1872 "Default Foreground", "Default Bold Foreground",
1873 "Default Background", "Default Bold Background",
1874 "Cursor Text", "Cursor Colour",
1875 "ANSI Black", "ANSI Black Bold",
1876 "ANSI Red", "ANSI Red Bold",
1877 "ANSI Green", "ANSI Green Bold",
1878 "ANSI Yellow", "ANSI Yellow Bold",
1879 "ANSI Blue", "ANSI Blue Bold",
1880 "ANSI Magenta", "ANSI Magenta Bold",
1881 "ANSI Cyan", "ANSI Cyan Bold",
1882 "ANSI White", "ANSI White Bold"
1884 static const int permanent[] = {
1885 TRUE, FALSE, TRUE, FALSE, TRUE, TRUE,
1886 TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE,
1887 TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE
1893 /* Accelerators used: [aco] bmlu */
1894 ctlposinit(&cp, hwnd);
1895 checkbox(&cp, "&Bolded text is a different colour", IDC5_BOLDCOLOUR);
1896 checkbox(&cp, "Attempt to use &logical palettes", IDC5_PALETTE);
1897 colouredit(&cp, "Select a colo&ur and click to modify it:",
1898 IDC5_STATIC, IDC5_LIST,
1899 "&Modify...", IDC5_CHANGE,
1900 "Red:", IDC5_RSTATIC, IDC5_RVALUE,
1901 "Green:", IDC5_GSTATIC, IDC5_GVALUE,
1902 "Blue:", IDC5_BSTATIC, IDC5_BVALUE, NULL);
1904 CheckDlgButton (hwnd, IDC5_BOLDCOLOUR, cfg.bold_colour);
1905 CheckDlgButton (hwnd, IDC5_PALETTE, cfg.try_palette);
1908 for (i=0; i<22; i++)
1909 if (cfg.bold_colour || permanent[i])
1910 SendDlgItemMessage (hwnd, IDC5_LIST, LB_ADDSTRING, 0,
1911 (LPARAM) colours[i]);
1913 SendDlgItemMessage (hwnd, IDC5_LIST, LB_SETCURSEL, 0, 0);
1914 SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[0][0], FALSE);
1915 SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[0][1], FALSE);
1916 SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[0][2], FALSE);
1919 switch (LOWORD(wParam)) {
1920 case IDC5_BOLDCOLOUR:
1921 if (HIWORD(wParam) == BN_CLICKED ||
1922 HIWORD(wParam) == BN_DOUBLECLICKED) {
1924 cfg.bold_colour = IsDlgButtonChecked (hwnd, IDC5_BOLDCOLOUR);
1925 n = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCOUNT, 0, 0);
1926 if (cfg.bold_colour && n!=22) {
1927 for (i=0; i<22; i++)
1929 SendDlgItemMessage (hwnd, IDC5_LIST,
1931 (LPARAM) colours[i]);
1932 } else if (!cfg.bold_colour && n!=12) {
1935 SendDlgItemMessage (hwnd, IDC5_LIST,
1936 LB_DELETESTRING, i, 0);
1941 if (HIWORD(wParam) == BN_CLICKED ||
1942 HIWORD(wParam) == BN_DOUBLECLICKED)
1943 cfg.try_palette = IsDlgButtonChecked (hwnd, IDC5_PALETTE);
1946 if (HIWORD(wParam) == LBN_DBLCLK ||
1947 HIWORD(wParam) == LBN_SELCHANGE) {
1948 int i = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCURSEL,
1950 if (!cfg.bold_colour)
1951 i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
1952 SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[i][0], FALSE);
1953 SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[i][1], FALSE);
1954 SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[i][2], FALSE);
1958 if (HIWORD(wParam) == BN_CLICKED ||
1959 HIWORD(wParam) == BN_DOUBLECLICKED) {
1960 static CHOOSECOLOR cc;
1961 static DWORD custom[16] = {0}; /* zero initialisers */
1962 int i = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCURSEL,
1964 if (!cfg.bold_colour)
1965 i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
1966 cc.lStructSize = sizeof(cc);
1967 cc.hwndOwner = hwnd;
1968 cc.hInstance = (HWND)hinst;
1969 cc.lpCustColors = custom;
1970 cc.rgbResult = RGB (cfg.colours[i][0], cfg.colours[i][1],
1972 cc.Flags = CC_FULLOPEN | CC_RGBINIT;
1973 if (ChooseColor(&cc)) {
1975 (unsigned char) (cc.rgbResult & 0xFF);
1977 (unsigned char) (cc.rgbResult >> 8) & 0xFF;
1979 (unsigned char) (cc.rgbResult >> 16) & 0xFF;
1980 SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[i][0],
1982 SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[i][1],
1984 SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[i][2],
1992 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1995 static int CALLBACK TranslationProc (HWND hwnd, UINT msg,
1996 WPARAM wParam, LPARAM lParam) {
2001 /* Accelerators used: [aco] beiknpsx */
2002 ctlposinit(&cp, hwnd);
2004 "Handling of VT100 line drawing characters:", IDC2_VTSTATIC,
2005 "Font has &XWindows encoding", IDC2_VTXWINDOWS,
2006 "Use font in &both ANSI and OEM modes", IDC2_VTOEMANSI,
2007 "Use font in O&EM mode only", IDC2_VTOEMONLY,
2008 "&Poor man's line drawing (""+"", ""-"" and ""|"")",
2009 IDC2_VTPOORMAN, NULL);
2011 "Character set translation:", IDC6_XLATSTATIC,
2012 "&None", IDC6_NOXLAT,
2013 "&KOI8 / Win-1251", IDC6_KOI8WIN1251,
2014 "&ISO-8859-2 / Win-1250", IDC6_88592WIN1250, NULL);
2015 checkbox(&cp, "CAP&S LOCK acts as cyrillic switch", IDC6_CAPSLOCKCYR);
2017 CheckRadioButton (hwnd, IDC6_NOXLAT, IDC6_88592WIN1250,
2018 cfg.xlat_88592w1250 ? IDC6_88592WIN1250 :
2019 cfg.xlat_enablekoiwin ? IDC6_KOI8WIN1251 :
2021 CheckDlgButton (hwnd, IDC6_CAPSLOCKCYR, cfg.xlat_capslockcyr);
2022 CheckRadioButton (hwnd, IDC2_VTXWINDOWS, IDC2_VTPOORMAN,
2023 cfg.vtmode == VT_XWINDOWS ? IDC2_VTXWINDOWS :
2024 cfg.vtmode == VT_OEMANSI ? IDC2_VTOEMANSI :
2025 cfg.vtmode == VT_OEMONLY ? IDC2_VTOEMONLY :
2028 switch (LOWORD(wParam)) {
2030 case IDC6_KOI8WIN1251:
2031 case IDC6_88592WIN1250:
2032 cfg.xlat_enablekoiwin =
2033 IsDlgButtonChecked (hwnd, IDC6_KOI8WIN1251);
2034 cfg.xlat_88592w1250 =
2035 IsDlgButtonChecked (hwnd, IDC6_88592WIN1250);
2037 case IDC6_CAPSLOCKCYR:
2038 if (HIWORD(wParam) == BN_CLICKED ||
2039 HIWORD(wParam) == BN_DOUBLECLICKED) {
2040 cfg.xlat_capslockcyr =
2041 IsDlgButtonChecked (hwnd, IDC6_CAPSLOCKCYR);
2044 case IDC2_VTXWINDOWS:
2045 case IDC2_VTOEMANSI:
2046 case IDC2_VTOEMONLY:
2047 case IDC2_VTPOORMAN:
2049 (IsDlgButtonChecked (hwnd, IDC2_VTXWINDOWS) ? VT_XWINDOWS :
2050 IsDlgButtonChecked (hwnd, IDC2_VTOEMANSI) ? VT_OEMANSI :
2051 IsDlgButtonChecked (hwnd, IDC2_VTOEMONLY) ? VT_OEMONLY :
2056 return GeneralPanelProc (hwnd, msg, wParam, lParam);
2059 static DLGPROC panelproc[NPANELS] = {
2060 ConnectionProc, KeyboardProc, TerminalProc, WindowProc,
2061 TelnetProc, SshProc, SelectionProc, ColourProc, TranslationProc
2063 static char *panelids[NPANELS] = {
2064 MAKEINTRESOURCE(IDD_PANEL0),
2065 MAKEINTRESOURCE(IDD_PANEL1),
2066 MAKEINTRESOURCE(IDD_PANEL2),
2067 MAKEINTRESOURCE(IDD_PANELW),
2068 MAKEINTRESOURCE(IDD_PANEL3),
2069 MAKEINTRESOURCE(IDD_PANEL35),
2070 MAKEINTRESOURCE(IDD_PANEL4),
2071 MAKEINTRESOURCE(IDD_PANEL5),
2072 MAKEINTRESOURCE(IDD_PANEL6)
2075 static char *names[NPANELS] = {
2076 "Connection", "Keyboard", "Terminal", "Window", "Telnet",
2077 "SSH", "Selection", "Colours", "Translation"
2080 static int mainp[MAIN_NPANELS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8};
2081 static int reconfp[RECONF_NPANELS] = { 1, 2, 3, 6, 7, 8};
2083 static HWND makesubdialog(HWND hwnd, int x, int y, int w, int h, int n) {
2087 r.left = x; r.top = y;
2088 r.right = r.left + w; r.bottom = r.top + h;
2089 MapDialogRect(hwnd, &r);
2090 ret = CreateWindowEx(WS_EX_CONTROLPARENT,
2091 WC_DIALOG, "", /* no title */
2092 WS_CHILD | WS_VISIBLE | DS_SETFONT,
2094 r.right-r.left, r.bottom-r.top,
2095 hwnd, (HMENU)(panelids[n]),
2097 SetWindowLong (ret, DWL_DLGPROC, (LONG)panelproc[n]);
2098 font = SendMessage(hwnd, WM_GETFONT, 0, 0);
2099 SendMessage (ret, WM_SETFONT, font, MAKELPARAM(0, 0));
2100 SendMessage (ret, WM_INITDIALOG, 0, 0);
2104 static int GenericMainDlgProc (HWND hwnd, UINT msg,
2105 WPARAM wParam, LPARAM lParam,
2106 int npanels, int *panelnums, HWND *page) {
2111 { /* centre the window */
2114 hw = GetDesktopWindow();
2115 if (GetWindowRect (hw, &rs) && GetWindowRect (hwnd, &rd))
2116 MoveWindow (hwnd, (rs.right + rs.left + rd.left - rd.right)/2,
2117 (rs.bottom + rs.top + rd.top - rd.bottom)/2,
2118 rd.right-rd.left, rd.bottom-rd.top, TRUE);
2122 r.left = 3; r.right = r.left + 174;
2123 r.top = 3; r.bottom = r.top + 193;
2124 MapDialogRect(hwnd, &r);
2125 tabctl = CreateWindowEx(0, WC_TABCONTROL, "",
2126 WS_CHILD | WS_VISIBLE |
2127 WS_TABSTOP | TCS_MULTILINE,
2129 r.right-r.left, r.bottom-r.top,
2130 hwnd, (HMENU)IDC_TAB, hinst, NULL);
2134 ctlposinit2(&cp, hwnd);
2135 ersatztab(&cp, "Category:", IDC_TABSTATIC1, IDC_TABLIST,
2138 WPARAM font = SendMessage(hwnd, WM_GETFONT, 0, 0);
2139 SendMessage(tabctl, WM_SETFONT, font, MAKELPARAM(TRUE, 0));
2143 if (tabctl) { /* initialise the tab control */
2147 for (i=0; i<npanels; i++) {
2148 tab.mask = TCIF_TEXT;
2149 tab.pszText = names[panelnums[i]];
2150 TabCtrl_InsertItem (tabctl, i, &tab);
2155 for (i=0; i<npanels; i++) {
2156 SendDlgItemMessage(hwnd, IDC_TABLIST, CB_ADDSTRING,
2157 0, (LPARAM)names[panelnums[i]]);
2159 SendDlgItemMessage(hwnd, IDC_TABLIST, CB_SETCURSEL, 0, 0);
2161 *page = makesubdialog(hwnd, 6, 30, 168, 163, panelnums[0]);
2165 if (LOWORD(wParam) == IDC_TAB &&
2166 ((LPNMHDR)lParam)->code == TCN_SELCHANGE) {
2167 int i = TabCtrl_GetCurSel(((LPNMHDR)lParam)->hwndFrom);
2169 DestroyWindow (*page);
2170 *page = makesubdialog(hwnd, 6, 30, 168, 163, panelnums[i]);
2171 SetFocus (((LPNMHDR)lParam)->hwndFrom); /* ensure focus stays */
2176 switch (LOWORD(wParam)) {
2178 if (HIWORD(wParam) == CBN_SELCHANGE) {
2179 HWND tablist = GetDlgItem (hwnd, IDC_TABLIST);
2180 int i = SendMessage (tablist, CB_GETCURSEL, 0, 0);
2182 DestroyWindow (*page);
2183 *page = makesubdialog(hwnd, 6, 30, 168, 163, panelnums[i]);
2184 SetFocus(tablist); /* ensure focus stays */
2190 EndDialog (hwnd, 1);
2195 EndDialog (hwnd, 0);
2200 EndDialog (hwnd, 0);
2203 /* Grrr Explorer will maximize Dialogs! */
2205 if (wParam == SIZE_MAXIMIZED)
2212 static int CALLBACK MainDlgProc (HWND hwnd, UINT msg,
2213 WPARAM wParam, LPARAM lParam) {
2218 static HWND page = NULL;
2220 if (msg == WM_COMMAND && LOWORD(wParam) == IDOK) {
2223 * If the Connection panel is active and the Session List
2224 * box is selected, we treat a press of Open to have an
2225 * implicit press of Load preceding it.
2227 hw = GetDlgItem (hwnd, IDC_TAB);
2228 i = TabCtrl_GetCurSel(hw);
2229 if (panelproc[mainp[i]] == ConnectionProc &&
2230 page && implicit_load_ok) {
2231 SendMessage (page, WM_COMMAND,
2232 MAKELONG(IDC0_SESSLOAD, BN_CLICKED), 0);
2236 if (msg == WM_COMMAND && LOWORD(wParam) == IDC_ABOUT) {
2237 EnableWindow(hwnd, 0);
2238 DialogBox(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
2239 GetParent(hwnd), AboutProc);
2240 EnableWindow(hwnd, 1);
2241 SetActiveWindow(hwnd);
2243 return GenericMainDlgProc (hwnd, msg, wParam, lParam,
2244 MAIN_NPANELS, mainp, &page);
2247 static int CALLBACK ReconfDlgProc (HWND hwnd, UINT msg,
2248 WPARAM wParam, LPARAM lParam) {
2250 return GenericMainDlgProc (hwnd, msg, wParam, lParam,
2251 RECONF_NPANELS, reconfp, &page);
2254 void get_sesslist(int allocate) {
2255 static char otherbuf[2048];
2256 static char *buffer;
2257 int buflen, bufsize, i;
2263 if ((handle = enum_settings_start()) == NULL)
2266 buflen = bufsize = 0;
2269 ret = enum_settings_next(handle, otherbuf, sizeof(otherbuf));
2271 int len = strlen(otherbuf)+1;
2272 if (bufsize < buflen+len) {
2273 bufsize = buflen + len + 2048;
2274 buffer = srealloc(buffer, bufsize);
2276 strcpy(buffer+buflen, otherbuf);
2277 buflen += strlen(buffer+buflen)+1;
2280 enum_settings_finish(handle);
2281 buffer = srealloc(buffer, buflen+1);
2282 buffer[buflen] = '\0';
2285 nsessions = 1; /* "Default Settings" counts as one */
2287 if (strcmp(p, "Default Settings"))
2293 sessions = smalloc(nsessions * sizeof(char *));
2294 sessions[0] = "Default Settings";
2298 if (strcmp(p, "Default Settings"))
2309 int do_config (void) {
2313 savedsession[0] = '\0';
2314 ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_MAINBOX), NULL, MainDlgProc);
2315 get_sesslist(FALSE);
2320 int do_reconfig (HWND hwnd) {
2324 backup_cfg = cfg; /* structure copy */
2325 ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_RECONF), hwnd, ReconfDlgProc);
2327 cfg = backup_cfg; /* structure copy */
2334 void do_defaults (char *session) {
2336 load_settings (session, TRUE);
2338 load_settings ("Default Settings", FALSE);
2341 void logevent (char *string) {
2342 if (nevents >= negsize) {
2344 events = srealloc (events, negsize * sizeof(*events));
2346 events[nevents] = smalloc(1+strlen(string));
2347 strcpy (events[nevents], string);
2351 SendDlgItemMessage (logbox, IDN_LIST, LB_ADDSTRING,
2353 count = SendDlgItemMessage (logbox, IDN_LIST, LB_GETCOUNT, 0, 0);
2354 SendDlgItemMessage (logbox, IDN_LIST, LB_SETTOPINDEX, count-1, 0);
2358 void showeventlog (HWND hwnd) {
2360 logbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_LOGBOX),
2362 ShowWindow (logbox, SW_SHOWNORMAL);
2366 void showabout (HWND hwnd) {
2368 abtbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
2370 ShowWindow (abtbox, SW_SHOWNORMAL);
2374 void verify_ssh_host_key(char *host, int port, char *keytype,
2375 char *keystr, char *fingerprint) {
2378 static const char absentmsg[] =
2379 "The server's host key is not cached in the registry. You\n"
2380 "have no guarantee that the server is the computer you\n"
2382 "The server's key fingerprint is:\n"
2384 "If you trust this host, hit Yes to add the key to\n"
2385 "PuTTY's cache and carry on connecting.\n"
2386 "If you do not trust this host, hit No to abandon the\n"
2389 static const char wrongmsg[] =
2390 "WARNING - POTENTIAL SECURITY BREACH!\n"
2392 "The server's host key does not match the one PuTTY has\n"
2393 "cached in the registry. This means that either the\n"
2394 "server administrator has changed the host key, or you\n"
2395 "have actually connected to another computer pretending\n"
2396 "to be the server.\n"
2397 "The new key fingerprint is:\n"
2399 "If you were expecting this change and trust the new key,\n"
2400 "hit Yes to update PuTTY's cache and continue connecting.\n"
2401 "If you want to carry on connecting but without updating\n"
2402 "the cache, hit No.\n"
2403 "If you want to abandon the connection completely, hit\n"
2404 "Cancel. Hitting Cancel is the ONLY guaranteed safe\n"
2407 static const char mbtitle[] = "PuTTY Security Alert";
2410 char message[160+ /* sensible fingerprint max size */
2411 (sizeof(absentmsg) > sizeof(wrongmsg) ?
2412 sizeof(absentmsg) : sizeof(wrongmsg))];
2415 * Verify the key against the registry.
2417 ret = verify_host_key(host, port, keytype, keystr);
2419 if (ret == 0) /* success - key matched OK */
2421 if (ret == 2) { /* key was different */
2423 sprintf(message, wrongmsg, fingerprint);
2424 mbret = MessageBox(NULL, message, mbtitle,
2425 MB_ICONWARNING | MB_YESNOCANCEL);
2427 store_host_key(host, port, keytype, keystr);
2428 if (mbret == IDCANCEL)
2431 if (ret == 1) { /* key was absent */
2433 sprintf(message, absentmsg, fingerprint);
2434 mbret = MessageBox(NULL, message, mbtitle,
2435 MB_ICONWARNING | MB_YESNO);
2438 store_host_key(host, port, keytype, keystr);