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) {
1055 enum { controlstartvalue = 1000,
1076 /* Accelerators used: [aco] dehlnprstwx */
1077 ctlposinit(&cp, hwnd);
1079 "Host &Name", IDC_HOSTSTATIC, IDC_HOST, 75,
1080 "&Port", IDC_PORTSTATIC, IDC_PORT, 25, NULL);
1081 radioline(&cp, "Protocol:", IDC_PROTSTATIC, 3,
1082 "&Raw", IDC_PROTRAW,
1083 "&Telnet", IDC_PROTTELNET,
1090 sesssaver(&cp, "Stor&ed Sessions",
1091 IDC_SESSSTATIC, IDC_SESSEDIT, IDC_SESSLIST,
1092 "&Load", IDC_SESSLOAD,
1093 "&Save", IDC_SESSSAVE,
1094 "&Delete", IDC_SESSDEL, NULL);
1095 checkbox(&cp, "Close Window on E&xit", IDC_CLOSEEXIT);
1096 checkbox(&cp, "&Warn on Close", IDC_CLOSEWARN);
1098 SetDlgItemText (hwnd, IDC_HOST, cfg.host);
1099 SetDlgItemText (hwnd, IDC_SESSEDIT, savedsession);
1100 SetDlgItemInt (hwnd, IDC_PORT, cfg.port, FALSE);
1101 for (i = 0; i < nsessions; i++)
1102 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_ADDSTRING,
1103 0, (LPARAM) (sessions[i]));
1104 CheckRadioButton (hwnd, IDC_PROTRAW, IDC_PROTSSH,
1105 cfg.protocol==PROT_SSH ? IDC_PROTSSH :
1106 cfg.protocol==PROT_TELNET ? IDC_PROTTELNET : IDC_PROTRAW );
1107 CheckDlgButton (hwnd, IDC_CLOSEEXIT, cfg.close_on_exit);
1108 CheckDlgButton (hwnd, IDC_CLOSEWARN, cfg.warn_on_close);
1112 * Button release should trigger WM_OK if there was a
1113 * previous double click on the session list.
1117 SendMessage (GetParent(hwnd), WM_COMMAND, IDOK, 0);
1120 switch (LOWORD(wParam)) {
1121 case IDC_PROTTELNET:
1124 if (HIWORD(wParam) == BN_CLICKED ||
1125 HIWORD(wParam) == BN_DOUBLECLICKED) {
1126 int i = IsDlgButtonChecked (hwnd, IDC_PROTSSH);
1127 int j = IsDlgButtonChecked (hwnd, IDC_PROTTELNET);
1128 cfg.protocol = i ? PROT_SSH : j ? PROT_TELNET : PROT_RAW ;
1129 if ((cfg.protocol == PROT_SSH && cfg.port == 23) ||
1130 (cfg.protocol == PROT_TELNET && cfg.port == 22)) {
1131 cfg.port = i ? 22 : 23;
1132 SetDlgItemInt (hwnd, IDC_PORT, cfg.port, FALSE);
1137 if (HIWORD(wParam) == EN_CHANGE)
1138 GetDlgItemText (hwnd, IDC_HOST, cfg.host,
1139 sizeof(cfg.host)-1);
1142 if (HIWORD(wParam) == EN_CHANGE)
1143 MyGetDlgItemInt (hwnd, IDC_PORT, &cfg.port);
1146 if (HIWORD(wParam) == BN_CLICKED ||
1147 HIWORD(wParam) == BN_DOUBLECLICKED)
1148 cfg.close_on_exit = IsDlgButtonChecked (hwnd, IDC_CLOSEEXIT);
1151 if (HIWORD(wParam) == BN_CLICKED ||
1152 HIWORD(wParam) == BN_DOUBLECLICKED)
1153 cfg.warn_on_close = IsDlgButtonChecked (hwnd, IDC_CLOSEWARN);
1156 if (HIWORD(wParam) == EN_CHANGE) {
1157 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL,
1159 GetDlgItemText (hwnd, IDC_SESSEDIT,
1160 savedsession, sizeof(savedsession)-1);
1161 savedsession[sizeof(savedsession)-1] = '\0';
1165 if (HIWORD(wParam) == BN_CLICKED ||
1166 HIWORD(wParam) == BN_DOUBLECLICKED) {
1171 GetDlgItemText (hwnd, IDC_SESSEDIT, str, sizeof(str)-1);
1173 int n = SendDlgItemMessage (hwnd, IDC_SESSLIST,
1174 LB_GETCURSEL, 0, 0);
1179 strcpy (str, sessions[n]);
1181 save_settings (str, !!strcmp(str, "Default Settings"));
1182 get_sesslist (FALSE);
1183 get_sesslist (TRUE);
1184 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_RESETCONTENT,
1186 for (i = 0; i < nsessions; i++)
1187 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_ADDSTRING,
1188 0, (LPARAM) (sessions[i]));
1189 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL,
1195 if (LOWORD(wParam) == IDC_SESSLOAD &&
1196 HIWORD(wParam) != BN_CLICKED &&
1197 HIWORD(wParam) != BN_DOUBLECLICKED)
1199 if (LOWORD(wParam) == IDC_SESSLIST &&
1200 HIWORD(wParam) != LBN_DBLCLK)
1203 int n = SendDlgItemMessage (hwnd, IDC_SESSLIST,
1204 LB_GETCURSEL, 0, 0);
1209 load_settings (sessions[n],
1210 !!strcmp(sessions[n], "Default Settings"));
1211 SetDlgItemText (hwnd, IDC_HOST, cfg.host);
1212 SetDlgItemInt (hwnd, IDC_PORT, cfg.port, FALSE);
1213 CheckRadioButton (hwnd, IDC_PROTRAW, IDC_PROTSSH,
1214 (cfg.protocol==PROT_SSH ? IDC_PROTSSH :
1215 cfg.protocol==PROT_TELNET ? IDC_PROTTELNET : IDC_PROTRAW));
1216 CheckDlgButton (hwnd, IDC_CLOSEEXIT, cfg.close_on_exit);
1217 CheckDlgButton (hwnd, IDC_CLOSEWARN, cfg.warn_on_close);
1218 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL,
1221 if (LOWORD(wParam) == IDC_SESSLIST) {
1223 * A double-click on a saved session should
1224 * actually start the session, not just load it.
1225 * Unless it's Default Settings or some other
1226 * host-less set of saved settings.
1235 if (HIWORD(wParam) == BN_CLICKED ||
1236 HIWORD(wParam) == BN_DOUBLECLICKED) {
1237 int n = SendDlgItemMessage (hwnd, IDC_SESSLIST,
1238 LB_GETCURSEL, 0, 0);
1239 if (n == LB_ERR || n == 0) {
1243 del_settings(sessions[n]);
1244 get_sesslist (FALSE);
1245 get_sesslist (TRUE);
1246 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_RESETCONTENT,
1248 for (i = 0; i < nsessions; i++)
1249 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_ADDSTRING,
1250 0, (LPARAM) (sessions[i]));
1251 SendDlgItemMessage (hwnd, IDC_SESSLIST, LB_SETCURSEL,
1256 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1259 static int CALLBACK KeyboardProc (HWND hwnd, UINT msg,
1260 WPARAM wParam, LPARAM lParam) {
1262 enum { controlstartvalue = 1000,
1288 /* Accelerators used: [aco] 4?ehiklmnprsuvxy */
1289 ctlposinit(&cp, hwnd);
1290 radioline(&cp, "Action of Backspace:", IDC_DELSTATIC, 2,
1291 "Control-&H", IDC_DEL008,
1292 "Control-&? (127)", IDC_DEL127, NULL);
1293 radioline(&cp, "Action of Home and End:", IDC_HOMESTATIC, 2,
1294 "&Standard", IDC_HOMETILDE,
1295 "&rxvt", IDC_HOMERXVT, NULL);
1296 radioline(&cp, "Function key and keypad layout:", IDC_FUNCSTATIC, 3,
1297 "&VT400", IDC_FUNCTILDE,
1298 "&Linux", IDC_FUNCLINUX,
1299 "&Xterm R6", IDC_FUNCXTERM, NULL);
1300 radioline(&cp, "Initial state of cursor keys:", IDC_CURSTATIC, 2,
1301 "&Normal", IDC_CURNORMAL,
1302 "A&pplication", IDC_CURAPPLIC, NULL);
1303 radioline(&cp, "Initial state of numeric keypad:", IDC_KPSTATIC, 3,
1304 "Nor&mal", IDC_KPNORMAL,
1305 "Appl&ication", IDC_KPAPPLIC,
1306 "N&etHack", IDC_KPNH, NULL);
1307 checkbox(&cp, "ALT-F&4 is special (closes window)", IDC_ALTF4);
1308 checkbox(&cp, "ALT-Space is special (S&ystem menu)", IDC_ALTSPACE);
1309 checkbox(&cp, "&Use local terminal line discipline", IDC_LDISCTERM);
1310 checkbox(&cp, "Reset scrollback on &keypress", IDC_SCROLLKEY);
1312 CheckRadioButton (hwnd, IDC_DEL008, IDC_DEL127,
1313 cfg.bksp_is_delete ? IDC_DEL127 : IDC_DEL008);
1314 CheckRadioButton (hwnd, IDC_HOMETILDE, IDC_HOMERXVT,
1315 cfg.rxvt_homeend ? IDC_HOMERXVT : IDC_HOMETILDE);
1316 CheckRadioButton (hwnd, IDC_FUNCTILDE, IDC_FUNCXTERM,
1318 (cfg.funky_type==2 ? IDC_FUNCXTERM
1321 CheckRadioButton (hwnd, IDC_CURNORMAL, IDC_CURAPPLIC,
1322 cfg.app_cursor ? IDC_CURAPPLIC : IDC_CURNORMAL);
1323 CheckRadioButton (hwnd, IDC_KPNORMAL, IDC_KPNH,
1324 cfg.nethack_keypad ? IDC_KPNH :
1325 cfg.app_keypad ? IDC_KPAPPLIC : IDC_KPNORMAL);
1326 CheckDlgButton (hwnd, IDC_ALTF4, cfg.alt_f4);
1327 CheckDlgButton (hwnd, IDC_ALTSPACE, cfg.alt_space);
1328 CheckDlgButton (hwnd, IDC_LDISCTERM, cfg.ldisc_term);
1329 CheckDlgButton (hwnd, IDC_SCROLLKEY, cfg.scroll_on_key);
1332 if (HIWORD(wParam) == BN_CLICKED ||
1333 HIWORD(wParam) == BN_DOUBLECLICKED)
1334 switch (LOWORD(wParam)) {
1337 cfg.bksp_is_delete = IsDlgButtonChecked (hwnd, IDC_DEL127);
1341 cfg.rxvt_homeend = IsDlgButtonChecked (hwnd, IDC_HOMERXVT);
1348 cfg.funky_type = IsDlgButtonChecked (hwnd, IDC_FUNCLINUX);
1352 cfg.app_keypad = IsDlgButtonChecked (hwnd, IDC_KPAPPLIC);
1353 cfg.nethack_keypad = FALSE;
1356 cfg.app_keypad = FALSE;
1357 cfg.nethack_keypad = TRUE;
1361 cfg.app_cursor = IsDlgButtonChecked (hwnd, IDC_CURAPPLIC);
1364 if (HIWORD(wParam) == BN_CLICKED ||
1365 HIWORD(wParam) == BN_DOUBLECLICKED)
1366 cfg.alt_f4 = IsDlgButtonChecked (hwnd, IDC_ALTF4);
1369 if (HIWORD(wParam) == BN_CLICKED ||
1370 HIWORD(wParam) == BN_DOUBLECLICKED)
1371 cfg.alt_space = IsDlgButtonChecked (hwnd, IDC_ALTSPACE);
1374 if (HIWORD(wParam) == BN_CLICKED ||
1375 HIWORD(wParam) == BN_DOUBLECLICKED)
1376 cfg.ldisc_term = IsDlgButtonChecked (hwnd, IDC_LDISCTERM);
1379 if (HIWORD(wParam) == BN_CLICKED ||
1380 HIWORD(wParam) == BN_DOUBLECLICKED)
1381 cfg.scroll_on_key = IsDlgButtonChecked (hwnd, IDC_SCROLLKEY);
1385 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1388 static void fmtfont (char *buf) {
1389 sprintf (buf, "Font: %s, ", cfg.font);
1391 strcat(buf, "bold, ");
1392 if (cfg.fontheight == 0)
1393 strcat (buf, "default height");
1395 sprintf (buf+strlen(buf), "%d-%s",
1396 (cfg.fontheight < 0 ? -cfg.fontheight : cfg.fontheight),
1397 (cfg.fontheight < 0 ? "pixel" : "point"));
1400 static int CALLBACK TerminalProc (HWND hwnd, UINT msg,
1401 WPARAM wParam, LPARAM lParam) {
1405 char fontstatic[256];
1406 enum { controlstartvalue = 1000,
1426 /* Accelerators used: [aco] dghlmnprsw */
1427 ctlposinit(&cp, hwnd);
1429 "&Rows", IDC_ROWSSTATIC, IDC_ROWSEDIT, 33,
1430 "Colu&mns", IDC_COLSSTATIC, IDC_COLSEDIT, 33,
1431 "&Scrollback", IDC_SAVESTATIC, IDC_SAVEEDIT, 33,
1433 staticbtn(&cp, "", IDC_FONTSTATIC, "C&hange...", IDC_CHOOSEFONT);
1434 checkbox(&cp, "Auto &wrap mode initially on", IDC_WRAPMODE);
1435 checkbox(&cp, "&DEC Origin Mode initially on", IDC_DECOM);
1436 checkbox(&cp, "Implicit CR in every &LF", IDC_LFHASCR);
1437 checkbox(&cp, "Bee&p enabled", IDC_BEEP);
1438 checkbox(&cp, "Use Back&ground colour erase", IDC_BCE);
1439 checkbox(&cp, "Enable bli&nking text", IDC_BLINKTEXT);
1441 CheckDlgButton (hwnd, IDC_WRAPMODE, cfg.wrap_mode);
1442 CheckDlgButton (hwnd, IDC_DECOM, cfg.dec_om);
1443 CheckDlgButton (hwnd, IDC_LFHASCR, cfg.lfhascr);
1444 SetDlgItemInt (hwnd, IDC_ROWSEDIT, cfg.height, FALSE);
1445 SetDlgItemInt (hwnd, IDC_COLSEDIT, cfg.width, FALSE);
1446 SetDlgItemInt (hwnd, IDC_SAVEEDIT, cfg.savelines, FALSE);
1447 fmtfont (fontstatic);
1448 SetDlgItemText (hwnd, IDC_FONTSTATIC, fontstatic);
1449 CheckDlgButton (hwnd, IDC_BEEP, cfg.beep);
1450 CheckDlgButton (hwnd, IDC_BCE, cfg.bce);
1451 CheckDlgButton (hwnd, IDC_BLINKTEXT, cfg.blinktext);
1454 switch (LOWORD(wParam)) {
1456 if (HIWORD(wParam) == BN_CLICKED ||
1457 HIWORD(wParam) == BN_DOUBLECLICKED)
1458 cfg.wrap_mode = IsDlgButtonChecked (hwnd, IDC_WRAPMODE);
1461 if (HIWORD(wParam) == BN_CLICKED ||
1462 HIWORD(wParam) == BN_DOUBLECLICKED)
1463 cfg.dec_om = IsDlgButtonChecked (hwnd, IDC_DECOM);
1466 if (HIWORD(wParam) == BN_CLICKED ||
1467 HIWORD(wParam) == BN_DOUBLECLICKED)
1468 cfg.lfhascr = IsDlgButtonChecked (hwnd, IDC_LFHASCR);
1471 if (HIWORD(wParam) == EN_CHANGE)
1472 MyGetDlgItemInt (hwnd, IDC_ROWSEDIT, &cfg.height);
1475 if (HIWORD(wParam) == EN_CHANGE)
1476 MyGetDlgItemInt (hwnd, IDC_COLSEDIT, &cfg.width);
1479 if (HIWORD(wParam) == EN_CHANGE)
1480 MyGetDlgItemInt (hwnd, IDC_SAVEEDIT, &cfg.savelines);
1482 case IDC_CHOOSEFONT:
1483 lf.lfHeight = cfg.fontheight;
1484 lf.lfWidth = lf.lfEscapement = lf.lfOrientation = 0;
1485 lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = 0;
1486 lf.lfWeight = (cfg.fontisbold ? FW_BOLD : 0);
1487 lf.lfCharSet = cfg.fontcharset;
1488 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
1489 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1490 lf.lfQuality = DEFAULT_QUALITY;
1491 lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
1492 strncpy (lf.lfFaceName, cfg.font, sizeof(lf.lfFaceName)-1);
1493 lf.lfFaceName[sizeof(lf.lfFaceName)-1] = '\0';
1495 cf.lStructSize = sizeof(cf);
1496 cf.hwndOwner = hwnd;
1498 cf.Flags = CF_FIXEDPITCHONLY | CF_FORCEFONTEXIST |
1499 CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
1501 if (ChooseFont (&cf)) {
1502 strncpy (cfg.font, lf.lfFaceName, sizeof(cfg.font)-1);
1503 cfg.font[sizeof(cfg.font)-1] = '\0';
1504 cfg.fontisbold = (lf.lfWeight == FW_BOLD);
1505 cfg.fontcharset = lf.lfCharSet;
1506 cfg.fontheight = lf.lfHeight;
1507 fmtfont (fontstatic);
1508 SetDlgItemText (hwnd, IDC_FONTSTATIC, fontstatic);
1512 if (HIWORD(wParam) == BN_CLICKED ||
1513 HIWORD(wParam) == BN_DOUBLECLICKED)
1514 cfg.beep = IsDlgButtonChecked (hwnd, IDC_BEEP);
1517 if (HIWORD(wParam) == BN_CLICKED ||
1518 HIWORD(wParam) == BN_DOUBLECLICKED)
1519 cfg.blinktext = IsDlgButtonChecked (hwnd, IDC_BLINKTEXT);
1522 if (HIWORD(wParam) == BN_CLICKED ||
1523 HIWORD(wParam) == BN_DOUBLECLICKED)
1524 cfg.bce = IsDlgButtonChecked (hwnd, IDC_BCE);
1529 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1532 static int CALLBACK WindowProc (HWND hwnd, UINT msg,
1533 WPARAM wParam, LPARAM lParam) {
1535 enum { controlstartvalue = 1000,
1546 /* Accelerators used: [aco] bikty */
1547 ctlposinit(&cp, hwnd);
1549 "Initial window &title:", IDC_WINTITLE, IDC_WINEDIT, 100,
1551 checkbox(&cp, "Avoid ever using &icon title", IDC_WINNAME);
1552 checkbox(&cp, "&Blinking cursor", IDC_BLINKCUR);
1553 checkbox(&cp, "Displa&y scrollbar", IDC_SCROLLBAR);
1554 checkbox(&cp, "Loc&k Window size", IDC_LOCKSIZE);
1556 SetDlgItemText (hwnd, IDC_WINEDIT, cfg.wintitle);
1557 CheckDlgButton (hwnd, IDC_WINNAME, cfg.win_name_always);
1558 CheckDlgButton (hwnd, IDC_BLINKCUR, cfg.blink_cur);
1559 CheckDlgButton (hwnd, IDC_SCROLLBAR, cfg.scrollbar);
1560 CheckDlgButton (hwnd, IDC_LOCKSIZE, cfg.locksize);
1563 switch (LOWORD(wParam)) {
1565 if (HIWORD(wParam) == BN_CLICKED ||
1566 HIWORD(wParam) == BN_DOUBLECLICKED)
1567 cfg.win_name_always = IsDlgButtonChecked (hwnd, IDC_WINNAME);
1570 if (HIWORD(wParam) == BN_CLICKED ||
1571 HIWORD(wParam) == BN_DOUBLECLICKED)
1572 cfg.blink_cur = IsDlgButtonChecked (hwnd, IDC_BLINKCUR);
1575 if (HIWORD(wParam) == BN_CLICKED ||
1576 HIWORD(wParam) == BN_DOUBLECLICKED)
1577 cfg.scrollbar = IsDlgButtonChecked (hwnd, IDC_SCROLLBAR);
1580 if (HIWORD(wParam) == BN_CLICKED ||
1581 HIWORD(wParam) == BN_DOUBLECLICKED)
1582 cfg.locksize = IsDlgButtonChecked (hwnd, IDC_LOCKSIZE);
1585 if (HIWORD(wParam) == EN_CHANGE)
1586 GetDlgItemText (hwnd, IDC_WINEDIT, cfg.wintitle,
1587 sizeof(cfg.wintitle)-1);
1592 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1595 static int CALLBACK TelnetProc (HWND hwnd, UINT msg,
1596 WPARAM wParam, LPARAM lParam) {
1599 enum { controlstartvalue = 1000,
1621 /* Accelerators used: [aco] bdflrstuv */
1622 ctlposinit(&cp, hwnd);
1623 staticedit(&cp, "Terminal-&type string", IDC_TTSTATIC, IDC_TTEDIT);
1624 staticedit(&cp, "Terminal-&speed string", IDC_TSSTATIC, IDC_TSEDIT);
1625 staticedit(&cp, "Auto-login &username", IDC_LOGSTATIC, IDC_LOGEDIT);
1626 envsetter(&cp, "Environment variables:", IDC_ENVSTATIC,
1627 "&Variable", IDC_VARSTATIC, IDC_VAREDIT,
1628 "Va&lue", IDC_VALSTATIC, IDC_VALEDIT,
1630 "A&dd", IDC_ENVADD, "&Remove", IDC_ENVREMOVE);
1631 radioline(&cp, "Handling of OLD_ENVIRON ambiguity:", IDC_EMSTATIC, 2,
1632 "&BSD (commonplace)", IDC_EMBSD,
1633 "R&FC 1408 (unusual)", IDC_EMRFC, NULL);
1635 SetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype);
1636 SetDlgItemText (hwnd, IDC_TSEDIT, cfg.termspeed);
1637 SetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username);
1639 char *p = cfg.environmt;
1641 SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_ADDSTRING, 0,
1646 CheckRadioButton (hwnd, IDC_EMBSD, IDC_EMRFC,
1647 cfg.rfc_environ ? IDC_EMRFC : IDC_EMBSD);
1650 switch (LOWORD(wParam)) {
1652 if (HIWORD(wParam) == EN_CHANGE)
1653 GetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype,
1654 sizeof(cfg.termtype)-1);
1657 if (HIWORD(wParam) == EN_CHANGE)
1658 GetDlgItemText (hwnd, IDC_TSEDIT, cfg.termspeed,
1659 sizeof(cfg.termspeed)-1);
1662 if (HIWORD(wParam) == EN_CHANGE)
1663 GetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username,
1664 sizeof(cfg.username)-1);
1668 cfg.rfc_environ = IsDlgButtonChecked (hwnd, IDC_EMRFC);
1671 if (HIWORD(wParam) == BN_CLICKED ||
1672 HIWORD(wParam) == BN_DOUBLECLICKED) {
1673 char str[sizeof(cfg.environmt)];
1675 GetDlgItemText (hwnd, IDC_VAREDIT, str, sizeof(str)-1);
1680 p = str + strlen(str);
1682 GetDlgItemText (hwnd, IDC_VALEDIT, p, sizeof(str)-1-(p-str));
1692 if ((p-cfg.environmt) + strlen(str) + 2 < sizeof(cfg.environmt)) {
1694 p[strlen(str)+1] = '\0';
1695 SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_ADDSTRING,
1697 SetDlgItemText (hwnd, IDC_VAREDIT, "");
1698 SetDlgItemText (hwnd, IDC_VALEDIT, "");
1700 MessageBox(hwnd, "Environment too big", "PuTTY Error",
1701 MB_OK | MB_ICONERROR);
1706 if (HIWORD(wParam) != BN_CLICKED &&
1707 HIWORD(wParam) != BN_DOUBLECLICKED)
1709 i = SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_GETCURSEL, 0, 0);
1715 SendDlgItemMessage (hwnd, IDC_ENVLIST, LB_DELETESTRING,
1742 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1745 static int CALLBACK SshProc (HWND hwnd, UINT msg,
1746 WPARAM wParam, LPARAM lParam) {
1749 char filename[sizeof(cfg.keyfile)];
1750 enum { controlstartvalue = 1000,
1774 /* Accelerators used: [aco] 123abdkmprtuw */
1775 ctlposinit(&cp, hwnd);
1776 staticedit(&cp, "Terminal-&type string", IDC_TTSTATIC, IDC_TTEDIT);
1777 staticedit(&cp, "Auto-login &username", IDC_LOGSTATIC, IDC_LOGEDIT);
1779 "&Remote command:", IDC_CMDSTATIC, IDC_CMDEDIT, 100,
1781 checkbox(&cp, "Don't allocate a &pseudo-terminal", IDC_NOPTY);
1782 checkbox(&cp, "Atte&mpt TIS or CryptoCard authentication",
1784 checkbox(&cp, "Allow &agent forwarding", IDC_AGENTFWD);
1785 editbutton(&cp, "Private &key file for authentication:",
1786 IDC_PKSTATIC, IDC_PKEDIT, "Bro&wse...", IDC_PKBUTTON);
1787 radioline(&cp, "Preferred SSH protocol version:",
1788 IDC_SSHPROTSTATIC, 2,
1789 "&1", IDC_SSHPROT1, "&2", IDC_SSHPROT2, NULL);
1790 radioline(&cp, "Preferred encryption algorithm:", IDC_CIPHERSTATIC, 3,
1791 "&3DES", IDC_CIPHER3DES,
1792 "&Blowfish", IDC_CIPHERBLOWF,
1793 "&DES", IDC_CIPHERDES, NULL);
1795 SetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype);
1796 SetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username);
1797 CheckDlgButton (hwnd, IDC_NOPTY, cfg.nopty);
1798 CheckDlgButton (hwnd, IDC_AGENTFWD, cfg.agentfwd);
1799 CheckRadioButton (hwnd, IDC_CIPHER3DES, IDC_CIPHERDES,
1800 cfg.cipher == CIPHER_BLOWFISH ? IDC_CIPHERBLOWF :
1801 cfg.cipher == CIPHER_DES ? IDC_CIPHERDES :
1803 CheckRadioButton (hwnd, IDC_SSHPROT1, IDC_SSHPROT2,
1804 cfg.sshprot == 1 ? IDC_SSHPROT1 : IDC_SSHPROT2);
1805 CheckDlgButton (hwnd, IDC_AUTHTIS, cfg.try_tis_auth);
1806 SetDlgItemText (hwnd, IDC_PKEDIT, cfg.keyfile);
1807 SetDlgItemText (hwnd, IDC_CMDEDIT, cfg.remote_cmd);
1810 switch (LOWORD(wParam)) {
1812 if (HIWORD(wParam) == EN_CHANGE)
1813 GetDlgItemText (hwnd, IDC_TTEDIT, cfg.termtype,
1814 sizeof(cfg.termtype)-1);
1817 if (HIWORD(wParam) == EN_CHANGE)
1818 GetDlgItemText (hwnd, IDC_LOGEDIT, cfg.username,
1819 sizeof(cfg.username)-1);
1822 if (HIWORD(wParam) == BN_CLICKED ||
1823 HIWORD(wParam) == BN_DOUBLECLICKED)
1824 cfg.nopty = IsDlgButtonChecked (hwnd, IDC_NOPTY);
1827 if (HIWORD(wParam) == BN_CLICKED ||
1828 HIWORD(wParam) == BN_DOUBLECLICKED)
1829 cfg.agentfwd = IsDlgButtonChecked (hwnd, IDC_AGENTFWD);
1831 case IDC_CIPHER3DES:
1832 case IDC_CIPHERBLOWF:
1834 if (HIWORD(wParam) == BN_CLICKED ||
1835 HIWORD(wParam) == BN_DOUBLECLICKED) {
1836 if (IsDlgButtonChecked (hwnd, IDC_CIPHER3DES))
1837 cfg.cipher = CIPHER_3DES;
1838 else if (IsDlgButtonChecked (hwnd, IDC_CIPHERBLOWF))
1839 cfg.cipher = CIPHER_BLOWFISH;
1840 else if (IsDlgButtonChecked (hwnd, IDC_CIPHERDES))
1841 cfg.cipher = CIPHER_DES;
1846 if (HIWORD(wParam) == BN_CLICKED ||
1847 HIWORD(wParam) == BN_DOUBLECLICKED) {
1848 if (IsDlgButtonChecked (hwnd, IDC_SSHPROT1))
1850 else if (IsDlgButtonChecked (hwnd, IDC_SSHPROT2))
1855 if (HIWORD(wParam) == BN_CLICKED ||
1856 HIWORD(wParam) == BN_DOUBLECLICKED)
1857 cfg.try_tis_auth = IsDlgButtonChecked (hwnd, IDC_AUTHTIS);
1860 if (HIWORD(wParam) == EN_CHANGE)
1861 GetDlgItemText (hwnd, IDC_PKEDIT, cfg.keyfile,
1862 sizeof(cfg.keyfile)-1);
1865 if (HIWORD(wParam) == EN_CHANGE)
1866 GetDlgItemText (hwnd, IDC_CMDEDIT, cfg.remote_cmd,
1867 sizeof(cfg.remote_cmd)-1);
1871 * FIXME: this crashes. Find out why.
1873 memset(&of, 0, sizeof(of));
1874 #ifdef OPENFILENAME_SIZE_VERSION_400
1875 of.lStructSize = OPENFILENAME_SIZE_VERSION_400;
1877 of.lStructSize = sizeof(of);
1879 of.hwndOwner = hwnd;
1880 of.lpstrFilter = "All Files\0*\0\0\0";
1881 of.lpstrCustomFilter = NULL;
1882 of.nFilterIndex = 1;
1883 of.lpstrFile = filename; strcpy(filename, cfg.keyfile);
1884 of.nMaxFile = sizeof(filename);
1885 of.lpstrFileTitle = NULL;
1886 of.lpstrInitialDir = NULL;
1887 of.lpstrTitle = "Select Public Key File";
1889 if (GetOpenFileName(&of)) {
1890 strcpy(cfg.keyfile, filename);
1891 SetDlgItemText (hwnd, IDC_PKEDIT, cfg.keyfile);
1897 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1900 static int CALLBACK SelectionProc (HWND hwnd, UINT msg,
1901 WPARAM wParam, LPARAM lParam) {
1904 enum { controlstartvalue = 1000,
1917 /* Accelerators used: [aco] stwx */
1918 ctlposinit(&cp, hwnd);
1919 radiobig(&cp, "Action of mouse buttons:", IDC_MBSTATIC,
1920 "&Windows (Right pastes, Middle extends)", IDC_MBWINDOWS,
1921 "&xterm (Right extends, Middle pastes)", IDC_MBXTERM,
1923 charclass(&cp, "Character classes:", IDC_CCSTATIC, IDC_CCLIST,
1924 "&Set", IDC_CCSET, IDC_CCEDIT,
1925 "&to class", IDC_CCSTATIC2);
1927 CheckRadioButton (hwnd, IDC_MBWINDOWS, IDC_MBXTERM,
1928 cfg.mouse_is_xterm ? IDC_MBXTERM : IDC_MBWINDOWS);
1930 static int tabs[4] = {25, 61, 96, 128};
1931 SendDlgItemMessage (hwnd, IDC_CCLIST, LB_SETTABSTOPS, 4,
1934 for (i=0; i<256; i++) {
1936 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
1937 (i>=0x21 && i != 0x7F) ? i : ' ',
1939 SendDlgItemMessage (hwnd, IDC_CCLIST, LB_ADDSTRING, 0,
1944 switch (LOWORD(wParam)) {
1947 cfg.mouse_is_xterm = IsDlgButtonChecked (hwnd, IDC_MBXTERM);
1953 int n = GetDlgItemInt (hwnd, IDC_CCEDIT, &ok, FALSE);
1958 for (i=0; i<256; i++)
1959 if (SendDlgItemMessage (hwnd, IDC_CCLIST, LB_GETSEL,
1962 cfg.wordness[i] = n;
1963 SendDlgItemMessage (hwnd, IDC_CCLIST,
1964 LB_DELETESTRING, i, 0);
1965 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
1966 (i>=0x21 && i != 0x7F) ? i : ' ',
1968 SendDlgItemMessage (hwnd, IDC_CCLIST,
1978 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1981 static int CALLBACK ColourProc (HWND hwnd, UINT msg,
1982 WPARAM wParam, LPARAM lParam) {
1983 static const char *const colours[] = {
1984 "Default Foreground", "Default Bold Foreground",
1985 "Default Background", "Default Bold Background",
1986 "Cursor Text", "Cursor Colour",
1987 "ANSI Black", "ANSI Black Bold",
1988 "ANSI Red", "ANSI Red Bold",
1989 "ANSI Green", "ANSI Green Bold",
1990 "ANSI Yellow", "ANSI Yellow Bold",
1991 "ANSI Blue", "ANSI Blue Bold",
1992 "ANSI Magenta", "ANSI Magenta Bold",
1993 "ANSI Cyan", "ANSI Cyan Bold",
1994 "ANSI White", "ANSI White Bold"
1996 static const int permanent[] = {
1997 TRUE, FALSE, TRUE, FALSE, TRUE, TRUE,
1998 TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE,
1999 TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE
2002 enum { controlstartvalue = 1000,
2018 /* Accelerators used: [aco] bmlu */
2019 ctlposinit(&cp, hwnd);
2020 checkbox(&cp, "&Bolded text is a different colour", IDC_BOLDCOLOUR);
2021 checkbox(&cp, "Attempt to use &logical palettes", IDC_PALETTE);
2022 colouredit(&cp, "Select a colo&ur and click to modify it:",
2023 IDC_STATIC, IDC_LIST,
2024 "&Modify...", IDC_CHANGE,
2025 "Red:", IDC_RSTATIC, IDC_RVALUE,
2026 "Green:", IDC_GSTATIC, IDC_GVALUE,
2027 "Blue:", IDC_BSTATIC, IDC_BVALUE, NULL);
2029 CheckDlgButton (hwnd, IDC_BOLDCOLOUR, cfg.bold_colour);
2030 CheckDlgButton (hwnd, IDC_PALETTE, cfg.try_palette);
2033 for (i=0; i<22; i++)
2034 if (cfg.bold_colour || permanent[i])
2035 SendDlgItemMessage (hwnd, IDC_LIST, LB_ADDSTRING, 0,
2036 (LPARAM) colours[i]);
2038 SendDlgItemMessage (hwnd, IDC_LIST, LB_SETCURSEL, 0, 0);
2039 SetDlgItemInt (hwnd, IDC_RVALUE, cfg.colours[0][0], FALSE);
2040 SetDlgItemInt (hwnd, IDC_GVALUE, cfg.colours[0][1], FALSE);
2041 SetDlgItemInt (hwnd, IDC_BVALUE, cfg.colours[0][2], FALSE);
2044 switch (LOWORD(wParam)) {
2045 case IDC_BOLDCOLOUR:
2046 if (HIWORD(wParam) == BN_CLICKED ||
2047 HIWORD(wParam) == BN_DOUBLECLICKED) {
2049 cfg.bold_colour = IsDlgButtonChecked (hwnd, IDC_BOLDCOLOUR);
2050 n = SendDlgItemMessage (hwnd, IDC_LIST, LB_GETCOUNT, 0, 0);
2051 if (cfg.bold_colour && n!=22) {
2052 for (i=0; i<22; i++)
2054 SendDlgItemMessage (hwnd, IDC_LIST,
2056 (LPARAM) colours[i]);
2057 } else if (!cfg.bold_colour && n!=12) {
2060 SendDlgItemMessage (hwnd, IDC_LIST,
2061 LB_DELETESTRING, i, 0);
2066 if (HIWORD(wParam) == BN_CLICKED ||
2067 HIWORD(wParam) == BN_DOUBLECLICKED)
2068 cfg.try_palette = IsDlgButtonChecked (hwnd, IDC_PALETTE);
2071 if (HIWORD(wParam) == LBN_DBLCLK ||
2072 HIWORD(wParam) == LBN_SELCHANGE) {
2073 int i = SendDlgItemMessage (hwnd, IDC_LIST, LB_GETCURSEL,
2075 if (!cfg.bold_colour)
2076 i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
2077 SetDlgItemInt (hwnd, IDC_RVALUE, cfg.colours[i][0], FALSE);
2078 SetDlgItemInt (hwnd, IDC_GVALUE, cfg.colours[i][1], FALSE);
2079 SetDlgItemInt (hwnd, IDC_BVALUE, cfg.colours[i][2], FALSE);
2083 if (HIWORD(wParam) == BN_CLICKED ||
2084 HIWORD(wParam) == BN_DOUBLECLICKED) {
2085 static CHOOSECOLOR cc;
2086 static DWORD custom[16] = {0}; /* zero initialisers */
2087 int i = SendDlgItemMessage (hwnd, IDC_LIST, LB_GETCURSEL,
2089 if (!cfg.bold_colour)
2090 i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
2091 cc.lStructSize = sizeof(cc);
2092 cc.hwndOwner = hwnd;
2093 cc.hInstance = (HWND)hinst;
2094 cc.lpCustColors = custom;
2095 cc.rgbResult = RGB (cfg.colours[i][0], cfg.colours[i][1],
2097 cc.Flags = CC_FULLOPEN | CC_RGBINIT;
2098 if (ChooseColor(&cc)) {
2100 (unsigned char) (cc.rgbResult & 0xFF);
2102 (unsigned char) (cc.rgbResult >> 8) & 0xFF;
2104 (unsigned char) (cc.rgbResult >> 16) & 0xFF;
2105 SetDlgItemInt (hwnd, IDC_RVALUE, cfg.colours[i][0],
2107 SetDlgItemInt (hwnd, IDC_GVALUE, cfg.colours[i][1],
2109 SetDlgItemInt (hwnd, IDC_BVALUE, cfg.colours[i][2],
2117 return GeneralPanelProc (hwnd, msg, wParam, lParam);
2120 static int CALLBACK TranslationProc (HWND hwnd, UINT msg,
2121 WPARAM wParam, LPARAM lParam) {
2123 enum { controlstartvalue = 1000,
2138 /* Accelerators used: [aco] beiknpsx */
2139 ctlposinit(&cp, hwnd);
2141 "Handling of VT100 line drawing characters:", IDC_VTSTATIC,
2142 "Font has &XWindows encoding", IDC_VTXWINDOWS,
2143 "Use font in &both ANSI and OEM modes", IDC_VTOEMANSI,
2144 "Use font in O&EM mode only", IDC_VTOEMONLY,
2145 "&Poor man's line drawing (""+"", ""-"" and ""|"")",
2146 IDC_VTPOORMAN, NULL);
2148 "Character set translation:", IDC_XLATSTATIC,
2149 "&None", IDC_NOXLAT,
2150 "&KOI8 / Win-1251", IDC_KOI8WIN1251,
2151 "&ISO-8859-2 / Win-1250", IDC_88592WIN1250, NULL);
2152 checkbox(&cp, "CAP&S LOCK acts as cyrillic switch", IDC_CAPSLOCKCYR);
2154 CheckRadioButton (hwnd, IDC_NOXLAT, IDC_88592WIN1250,
2155 cfg.xlat_88592w1250 ? IDC_88592WIN1250 :
2156 cfg.xlat_enablekoiwin ? IDC_KOI8WIN1251 :
2158 CheckDlgButton (hwnd, IDC_CAPSLOCKCYR, cfg.xlat_capslockcyr);
2159 CheckRadioButton (hwnd, IDC_VTXWINDOWS, IDC_VTPOORMAN,
2160 cfg.vtmode == VT_XWINDOWS ? IDC_VTXWINDOWS :
2161 cfg.vtmode == VT_OEMANSI ? IDC_VTOEMANSI :
2162 cfg.vtmode == VT_OEMONLY ? IDC_VTOEMONLY :
2165 switch (LOWORD(wParam)) {
2167 case IDC_KOI8WIN1251:
2168 case IDC_88592WIN1250:
2169 cfg.xlat_enablekoiwin =
2170 IsDlgButtonChecked (hwnd, IDC_KOI8WIN1251);
2171 cfg.xlat_88592w1250 =
2172 IsDlgButtonChecked (hwnd, IDC_88592WIN1250);
2174 case IDC_CAPSLOCKCYR:
2175 if (HIWORD(wParam) == BN_CLICKED ||
2176 HIWORD(wParam) == BN_DOUBLECLICKED) {
2177 cfg.xlat_capslockcyr =
2178 IsDlgButtonChecked (hwnd, IDC_CAPSLOCKCYR);
2181 case IDC_VTXWINDOWS:
2186 (IsDlgButtonChecked (hwnd, IDC_VTXWINDOWS) ? VT_XWINDOWS :
2187 IsDlgButtonChecked (hwnd, IDC_VTOEMANSI) ? VT_OEMANSI :
2188 IsDlgButtonChecked (hwnd, IDC_VTOEMONLY) ? VT_OEMONLY :
2193 return GeneralPanelProc (hwnd, msg, wParam, lParam);
2196 static DLGPROC panelproc[NPANELS] = {
2197 ConnectionProc, KeyboardProc, TerminalProc, WindowProc,
2198 TelnetProc, SshProc, SelectionProc, ColourProc, TranslationProc
2201 static char *names[NPANELS] = {
2202 "Connection", "Keyboard", "Terminal", "Window", "Telnet",
2203 "SSH", "Selection", "Colours", "Translation"
2206 static int mainp[MAIN_NPANELS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8};
2207 static int reconfp[RECONF_NPANELS] = { 1, 2, 3, 6, 7, 8};
2209 static HWND makesubdialog(HWND hwnd, int x, int y, int w, int h, int n) {
2213 r.left = x; r.top = y;
2214 r.right = r.left + w; r.bottom = r.top + h;
2215 MapDialogRect(hwnd, &r);
2216 ret = CreateWindowEx(WS_EX_CONTROLPARENT,
2217 WC_DIALOG, "", /* no title */
2218 WS_CHILD | WS_VISIBLE | DS_SETFONT,
2220 r.right-r.left, r.bottom-r.top,
2221 hwnd, (HMENU)IDC_SUBDLG,
2223 SetWindowLong (ret, DWL_DLGPROC, (LONG)panelproc[n]);
2224 font = SendMessage(hwnd, WM_GETFONT, 0, 0);
2225 SendMessage (ret, WM_SETFONT, font, MAKELPARAM(0, 0));
2226 SendMessage (ret, WM_INITDIALOG, 0, 0);
2230 static int GenericMainDlgProc (HWND hwnd, UINT msg,
2231 WPARAM wParam, LPARAM lParam,
2232 int npanels, int *panelnums, HWND *page) {
2237 { /* centre the window */
2240 hw = GetDesktopWindow();
2241 if (GetWindowRect (hw, &rs) && GetWindowRect (hwnd, &rd))
2242 MoveWindow (hwnd, (rs.right + rs.left + rd.left - rd.right)/2,
2243 (rs.bottom + rs.top + rd.top - rd.bottom)/2,
2244 rd.right-rd.left, rd.bottom-rd.top, TRUE);
2248 r.left = 3; r.right = r.left + 174;
2249 r.top = 3; r.bottom = r.top + 193;
2250 MapDialogRect(hwnd, &r);
2251 tabctl = CreateWindowEx(0, WC_TABCONTROL, "",
2252 WS_CHILD | WS_VISIBLE |
2253 WS_TABSTOP | TCS_MULTILINE,
2255 r.right-r.left, r.bottom-r.top,
2256 hwnd, (HMENU)IDC_TAB, hinst, NULL);
2260 ctlposinit2(&cp, hwnd);
2261 ersatztab(&cp, "Category:", IDC_TABSTATIC1, IDC_TABLIST,
2264 WPARAM font = SendMessage(hwnd, WM_GETFONT, 0, 0);
2265 SendMessage(tabctl, WM_SETFONT, font, MAKELPARAM(TRUE, 0));
2269 if (tabctl) { /* initialise the tab control */
2273 for (i=0; i<npanels; i++) {
2274 tab.mask = TCIF_TEXT;
2275 tab.pszText = names[panelnums[i]];
2276 TabCtrl_InsertItem (tabctl, i, &tab);
2281 for (i=0; i<npanels; i++) {
2282 SendDlgItemMessage(hwnd, IDC_TABLIST, CB_ADDSTRING,
2283 0, (LPARAM)names[panelnums[i]]);
2285 SendDlgItemMessage(hwnd, IDC_TABLIST, CB_SETCURSEL, 0, 0);
2287 *page = makesubdialog(hwnd, 6, 30, 168, 163, panelnums[0]);
2291 if (LOWORD(wParam) == IDC_TAB &&
2292 ((LPNMHDR)lParam)->code == TCN_SELCHANGE) {
2293 int i = TabCtrl_GetCurSel(((LPNMHDR)lParam)->hwndFrom);
2295 DestroyWindow (*page);
2296 *page = makesubdialog(hwnd, 6, 30, 168, 163, panelnums[i]);
2297 SetFocus (((LPNMHDR)lParam)->hwndFrom); /* ensure focus stays */
2302 switch (LOWORD(wParam)) {
2304 if (HIWORD(wParam) == CBN_SELCHANGE) {
2305 HWND tablist = GetDlgItem (hwnd, IDC_TABLIST);
2306 int i = SendMessage (tablist, CB_GETCURSEL, 0, 0);
2308 DestroyWindow (*page);
2309 *page = makesubdialog(hwnd, 6, 30, 168, 163, panelnums[i]);
2310 SetFocus(tablist); /* ensure focus stays */
2316 EndDialog (hwnd, 1);
2321 EndDialog (hwnd, 0);
2326 EndDialog (hwnd, 0);
2329 /* Grrr Explorer will maximize Dialogs! */
2331 if (wParam == SIZE_MAXIMIZED)
2338 static int CALLBACK MainDlgProc (HWND hwnd, UINT msg,
2339 WPARAM wParam, LPARAM lParam) {
2340 static HWND page = NULL;
2342 if (msg == WM_COMMAND && LOWORD(wParam) == IDOK) {
2344 if (msg == WM_COMMAND && LOWORD(wParam) == IDC_ABOUT) {
2345 EnableWindow(hwnd, 0);
2346 DialogBox(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
2347 GetParent(hwnd), AboutProc);
2348 EnableWindow(hwnd, 1);
2349 SetActiveWindow(hwnd);
2351 return GenericMainDlgProc (hwnd, msg, wParam, lParam,
2352 MAIN_NPANELS, mainp, &page);
2355 static int CALLBACK ReconfDlgProc (HWND hwnd, UINT msg,
2356 WPARAM wParam, LPARAM lParam) {
2358 return GenericMainDlgProc (hwnd, msg, wParam, lParam,
2359 RECONF_NPANELS, reconfp, &page);
2362 void get_sesslist(int allocate) {
2363 static char otherbuf[2048];
2364 static char *buffer;
2365 int buflen, bufsize, i;
2371 if ((handle = enum_settings_start()) == NULL)
2374 buflen = bufsize = 0;
2377 ret = enum_settings_next(handle, otherbuf, sizeof(otherbuf));
2379 int len = strlen(otherbuf)+1;
2380 if (bufsize < buflen+len) {
2381 bufsize = buflen + len + 2048;
2382 buffer = srealloc(buffer, bufsize);
2384 strcpy(buffer+buflen, otherbuf);
2385 buflen += strlen(buffer+buflen)+1;
2388 enum_settings_finish(handle);
2389 buffer = srealloc(buffer, buflen+1);
2390 buffer[buflen] = '\0';
2393 nsessions = 1; /* "Default Settings" counts as one */
2395 if (strcmp(p, "Default Settings"))
2401 sessions = smalloc(nsessions * sizeof(char *));
2402 sessions[0] = "Default Settings";
2406 if (strcmp(p, "Default Settings"))
2417 int do_config (void) {
2421 savedsession[0] = '\0';
2422 ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_MAINBOX), NULL, MainDlgProc);
2423 get_sesslist(FALSE);
2428 int do_reconfig (HWND hwnd) {
2432 backup_cfg = cfg; /* structure copy */
2433 ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_RECONF), hwnd, ReconfDlgProc);
2435 cfg = backup_cfg; /* structure copy */
2442 void do_defaults (char *session) {
2444 load_settings (session, TRUE);
2446 load_settings ("Default Settings", FALSE);
2449 void logevent (char *string) {
2450 if (nevents >= negsize) {
2452 events = srealloc (events, negsize * sizeof(*events));
2454 events[nevents] = smalloc(1+strlen(string));
2455 strcpy (events[nevents], string);
2459 SendDlgItemMessage (logbox, IDN_LIST, LB_ADDSTRING,
2461 count = SendDlgItemMessage (logbox, IDN_LIST, LB_GETCOUNT, 0, 0);
2462 SendDlgItemMessage (logbox, IDN_LIST, LB_SETTOPINDEX, count-1, 0);
2466 void showeventlog (HWND hwnd) {
2468 logbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_LOGBOX),
2470 ShowWindow (logbox, SW_SHOWNORMAL);
2474 void showabout (HWND hwnd) {
2476 abtbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
2478 ShowWindow (abtbox, SW_SHOWNORMAL);
2482 void verify_ssh_host_key(char *host, int port, char *keytype,
2483 char *keystr, char *fingerprint) {
2486 static const char absentmsg[] =
2487 "The server's host key is not cached in the registry. You\n"
2488 "have no guarantee that the server is the computer you\n"
2490 "The server's key fingerprint is:\n"
2492 "If you trust this host, hit Yes to add the key to\n"
2493 "PuTTY's cache and carry on connecting.\n"
2494 "If you do not trust this host, hit No to abandon the\n"
2497 static const char wrongmsg[] =
2498 "WARNING - POTENTIAL SECURITY BREACH!\n"
2500 "The server's host key does not match the one PuTTY has\n"
2501 "cached in the registry. This means that either the\n"
2502 "server administrator has changed the host key, or you\n"
2503 "have actually connected to another computer pretending\n"
2504 "to be the server.\n"
2505 "The new key fingerprint is:\n"
2507 "If you were expecting this change and trust the new key,\n"
2508 "hit Yes to update PuTTY's cache and continue connecting.\n"
2509 "If you want to carry on connecting but without updating\n"
2510 "the cache, hit No.\n"
2511 "If you want to abandon the connection completely, hit\n"
2512 "Cancel. Hitting Cancel is the ONLY guaranteed safe\n"
2515 static const char mbtitle[] = "PuTTY Security Alert";
2518 char message[160+ /* sensible fingerprint max size */
2519 (sizeof(absentmsg) > sizeof(wrongmsg) ?
2520 sizeof(absentmsg) : sizeof(wrongmsg))];
2523 * Verify the key against the registry.
2525 ret = verify_host_key(host, port, keytype, keystr);
2527 if (ret == 0) /* success - key matched OK */
2529 if (ret == 2) { /* key was different */
2531 sprintf(message, wrongmsg, fingerprint);
2532 mbret = MessageBox(NULL, message, mbtitle,
2533 MB_ICONWARNING | MB_YESNOCANCEL);
2535 store_host_key(host, port, keytype, keystr);
2536 if (mbret == IDCANCEL)
2539 if (ret == 1) { /* key was absent */
2541 sprintf(message, absentmsg, fingerprint);
2542 mbret = MessageBox(NULL, message, mbtitle,
2543 MB_ICONWARNING | MB_YESNO);
2546 store_host_key(host, port, keytype, keystr);