13 #define MAIN_NPANELS 7
14 #define RECONF_NPANELS 4
16 static const char *const puttystr = PUTTY_REG_POS "\\Sessions";
18 static void get_sesslist(int allocate);
20 static char **negots = NULL;
21 static int nnegots = 0, negsize = 0;
22 static HWND logbox = NULL, abtbox = NULL;
24 static char hex[16] = "0123456789ABCDEF";
26 static void mungestr(char *in, char *out) {
30 if (*in == ' ' || *in == '\\' || *in == '*' || *in == '?' ||
31 *in == '%' || *in < ' ' || *in > '~' || (*in == '.' && !candot)) {
33 *out++ = hex[((unsigned char)*in) >> 4];
34 *out++ = hex[((unsigned char)*in) & 15];
44 static void unmungestr(char *in, char *out) {
48 if (*in == '%' && in[1] && in[2]) {
51 i = in[1] - '0'; i -= (i > 9 ? 7 : 0);
52 j = in[2] - '0'; j -= (j > 9 ? 7 : 0);
63 static void wpps(HKEY key, LPCTSTR name, LPCTSTR value) {
64 RegSetValueEx(key, name, 0, REG_SZ, value, 1+strlen(value));
67 static void wppi(HKEY key, LPCTSTR name, int value) {
68 RegSetValueEx(key, name, 0, REG_DWORD,
69 (CONST BYTE *)&value, sizeof(value));
72 static void gpps(HKEY key, LPCTSTR name, LPCTSTR def,
73 LPTSTR val, int len) {
78 RegQueryValueEx(key, name, 0, &type, val, &size) != ERROR_SUCCESS ||
80 strncpy(val, def, len);
85 static void gppi(HKEY key, LPCTSTR name, int def, int *i) {
86 DWORD type, val, size;
90 RegQueryValueEx(key, name, 0, &type,
91 (BYTE *)&val, &size) != ERROR_SUCCESS ||
92 size != sizeof(val) || type != REG_DWORD)
101 char dataspace[2048];
104 static HINSTANCE hinst;
106 static char **sessions;
107 static int nsessions;
109 static void save_settings (char *section, int do_host) {
111 HKEY subkey1, sesskey;
114 p = malloc(3*strlen(section)+1);
115 mungestr(section, p);
117 if (RegCreateKey(HKEY_CURRENT_USER, puttystr, &subkey1)!=ERROR_SUCCESS ||
118 RegCreateKey(subkey1, p, &sesskey) != ERROR_SUCCESS) {
124 RegCloseKey(subkey1);
126 wppi (sesskey, "Present", 1);
128 wpps (sesskey, "HostName", cfg.host);
129 wppi (sesskey, "PortNumber", cfg.port);
130 wpps (sesskey, "Protocol",
131 cfg.protocol == PROT_SSH ? "ssh" : "telnet");
133 wppi (sesskey, "CloseOnExit", !!cfg.close_on_exit);
134 wpps (sesskey, "TerminalType", cfg.termtype);
135 wpps (sesskey, "TerminalSpeed", cfg.termspeed);
137 char buf[2*sizeof(cfg.environmt)], *p, *q;
143 if (c == '=' || c == ',' || c == '\\')
153 wpps (sesskey, "Environment", buf);
155 wpps (sesskey, "UserName", cfg.username);
156 wppi (sesskey, "NoPTY", cfg.nopty);
157 wppi (sesskey, "RFCEnviron", cfg.rfc_environ);
158 wppi (sesskey, "BackspaceIsDelete", cfg.bksp_is_delete);
159 wppi (sesskey, "RXVTHomeEnd", cfg.rxvt_homeend);
160 wppi (sesskey, "LinuxFunctionKeys", cfg.linux_funkeys);
161 wppi (sesskey, "ApplicationCursorKeys", cfg.app_cursor);
162 wppi (sesskey, "ApplicationKeypad", cfg.app_keypad);
163 wppi (sesskey, "ScrollbackLines", cfg.savelines);
164 wppi (sesskey, "DECOriginMode", cfg.dec_om);
165 wppi (sesskey, "AutoWrapMode", cfg.wrap_mode);
166 wppi (sesskey, "LFImpliesCR", cfg.lfhascr);
167 wppi (sesskey, "WinNameAlways", cfg.win_name_always);
168 wppi (sesskey, "TermWidth", cfg.width);
169 wppi (sesskey, "TermHeight", cfg.height);
170 wpps (sesskey, "Font", cfg.font);
171 wppi (sesskey, "FontIsBold", cfg.fontisbold);
172 wppi (sesskey, "FontHeight", cfg.fontheight);
173 wppi (sesskey, "FontVTMode", cfg.vtmode);
174 wppi (sesskey, "TryPalette", cfg.try_palette);
175 wppi (sesskey, "BoldAsColour", cfg.bold_colour);
176 for (i=0; i<22; i++) {
177 char buf[20], buf2[30];
178 sprintf(buf, "Colour%d", i);
179 sprintf(buf2, "%d,%d,%d", cfg.colours[i][0],
180 cfg.colours[i][1], cfg.colours[i][2]);
181 wpps (sesskey, buf, buf2);
183 wppi (sesskey, "MouseIsXterm", cfg.mouse_is_xterm);
184 for (i=0; i<256; i+=32) {
185 char buf[20], buf2[256];
187 sprintf(buf, "Wordness%d", i);
189 for (j=i; j<i+32; j++) {
190 sprintf(buf2+strlen(buf2), "%s%d",
191 (*buf2 ? "," : ""), cfg.wordness[j]);
193 wpps (sesskey, buf, buf2);
196 RegCloseKey(sesskey);
199 static void del_session (char *section) {
203 if (RegOpenKey(HKEY_CURRENT_USER, puttystr, &subkey1) != ERROR_SUCCESS)
206 p = malloc(3*strlen(section)+1);
207 mungestr(section, p);
208 RegDeleteKey(subkey1, p);
211 RegCloseKey(subkey1);
214 static void load_settings (char *section, int do_host) {
216 HKEY subkey1, sesskey;
219 p = malloc(3*strlen(section)+1);
220 mungestr(section, p);
222 if (RegOpenKey(HKEY_CURRENT_USER, puttystr, &subkey1) != ERROR_SUCCESS ||
223 RegOpenKey(subkey1, p, &sesskey) != ERROR_SUCCESS) {
229 RegCloseKey(subkey1);
233 gpps (sesskey, "HostName", "", cfg.host, sizeof(cfg.host));
234 gppi (sesskey, "PortNumber", 23, &cfg.port);
235 gpps (sesskey, "Protocol", "telnet", prot, 10);
236 if (!strcmp(prot, "ssh"))
237 cfg.protocol = PROT_SSH;
239 cfg.protocol = PROT_TELNET;
244 gppi (sesskey, "CloseOnExit", 1, &cfg.close_on_exit);
245 gpps (sesskey, "TerminalType", "xterm", cfg.termtype,
246 sizeof(cfg.termtype));
247 gpps (sesskey, "TerminalSpeed", "38400,38400", cfg.termspeed,
248 sizeof(cfg.termspeed));
250 char buf[2*sizeof(cfg.environmt)], *p, *q;
251 gpps (sesskey, "Environment", "", buf, sizeof(buf));
255 while (*p && *p != ',') {
268 gpps (sesskey, "UserName", "", cfg.username, sizeof(cfg.username));
269 gppi (sesskey, "NoPTY", 0, &cfg.nopty);
270 gppi (sesskey, "RFCEnviron", 0, &cfg.rfc_environ);
271 gppi (sesskey, "BackspaceIsDelete", 1, &cfg.bksp_is_delete);
272 gppi (sesskey, "RXVTHomeEnd", 0, &cfg.rxvt_homeend);
273 gppi (sesskey, "LinuxFunctionKeys", 0, &cfg.linux_funkeys);
274 gppi (sesskey, "ApplicationCursorKeys", 0, &cfg.app_cursor);
275 gppi (sesskey, "ApplicationKeypad", 0, &cfg.app_keypad);
276 gppi (sesskey, "ScrollbackLines", 200, &cfg.savelines);
277 gppi (sesskey, "DECOriginMode", 0, &cfg.dec_om);
278 gppi (sesskey, "AutoWrapMode", 1, &cfg.wrap_mode);
279 gppi (sesskey, "LFImpliesCR", 0, &cfg.lfhascr);
280 gppi (sesskey, "WinNameAlways", 0, &cfg.win_name_always);
281 gppi (sesskey, "TermWidth", 80, &cfg.width);
282 gppi (sesskey, "TermHeight", 24, &cfg.height);
283 gpps (sesskey, "Font", "Courier", cfg.font, sizeof(cfg.font));
284 gppi (sesskey, "FontIsBold", 0, &cfg.fontisbold);
285 gppi (sesskey, "FontHeight", 10, &cfg.fontheight);
286 gppi (sesskey, "FontVTMode", VT_POORMAN, &cfg.vtmode);
287 gppi (sesskey, "TryPalette", 0, &cfg.try_palette);
288 gppi (sesskey, "BoldAsColour", 1, &cfg.bold_colour);
289 for (i=0; i<22; i++) {
290 static char *defaults[] = {
291 "187,187,187", "255,255,255", "0,0,0", "85,85,85", "0,0,0",
292 "0,255,0", "0,0,0", "85,85,85", "187,0,0", "255,85,85",
293 "0,187,0", "85,255,85", "187,187,0", "255,255,85", "0,0,187",
294 "85,85,255", "187,0,187", "255,85,255", "0,187,187",
295 "85,255,255", "187,187,187", "255,255,255"
297 char buf[20], buf2[30];
298 sprintf(buf, "Colour%d", i);
299 gpps (sesskey, buf, defaults[i], buf2, sizeof(buf2));
300 sscanf(buf2, "%d,%d,%d", &cfg.colours[i][0],
301 &cfg.colours[i][1], &cfg.colours[i][2]);
303 gppi (sesskey, "MouseIsXterm", 0, &cfg.mouse_is_xterm);
304 for (i=0; i<256; i+=32) {
305 static char *defaults[] = {
306 "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",
307 "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",
308 "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",
309 "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",
310 "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",
311 "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",
312 "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",
313 "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"
315 char buf[20], buf2[256], *p;
317 sprintf(buf, "Wordness%d", i);
318 gpps (sesskey, buf, defaults[i/32], buf2, sizeof(buf2));
320 for (j=i; j<i+32; j++) {
322 while (*p && *p != ',') p++;
323 if (*p == ',') *p++ = '\0';
324 cfg.wordness[j] = atoi(q);
327 RegCloseKey(sesskey);
330 static void MyGetDlgItemInt (HWND hwnd, int id, int *result) {
333 n = GetDlgItemInt (hwnd, id, &ok, FALSE);
338 static int CALLBACK LogProc (HWND hwnd, UINT msg,
339 WPARAM wParam, LPARAM lParam) {
344 for (i=0; i<nnegots; i++)
345 SendDlgItemMessage (hwnd, IDN_LIST, LB_ADDSTRING,
346 0, (LPARAM)negots[i]);
348 /* case WM_CTLCOLORDLG: */
349 /* return (int) GetStockObject (LTGRAY_BRUSH); */
351 switch (LOWORD(wParam)) {
354 DestroyWindow (hwnd);
360 DestroyWindow (hwnd);
366 static int CALLBACK AboutProc (HWND hwnd, UINT msg,
367 WPARAM wParam, LPARAM lParam) {
370 SetDlgItemText (hwnd, IDA_VERSION, ver);
372 /* case WM_CTLCOLORDLG: */
373 /* return (int) GetStockObject (LTGRAY_BRUSH); */
374 /* case WM_CTLCOLORSTATIC: */
375 /* SetBkColor ((HDC)wParam, RGB(192,192,192)); */
376 /* return (int) GetStockObject (LTGRAY_BRUSH); */
378 switch (LOWORD(wParam)) {
381 DestroyWindow (hwnd);
384 EnableWindow(hwnd, 0);
385 DialogBox (hinst, MAKEINTRESOURCE(IDD_LICENCEBOX),
387 EnableWindow(hwnd, 1);
393 DestroyWindow (hwnd);
399 static int GeneralPanelProc (HWND hwnd, UINT msg,
400 WPARAM wParam, LPARAM lParam) {
403 SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
405 /* case WM_CTLCOLORDLG: */
406 /* return (int) GetStockObject (LTGRAY_BRUSH); */
407 /* case WM_CTLCOLORSTATIC: */
408 /* case WM_CTLCOLORBTN: */
409 /* SetBkColor ((HDC)wParam, RGB(192,192,192)); */
410 /* return (int) GetStockObject (LTGRAY_BRUSH); */
412 DestroyWindow (hwnd);
418 static int CALLBACK ConnectionProc (HWND hwnd, UINT msg,
419 WPARAM wParam, LPARAM lParam) {
424 SetDlgItemText (hwnd, IDC0_HOST, cfg.host);
425 SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE);
426 for (i = 0; i < nsessions; i++)
427 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING,
428 0, (LPARAM) (sessions[i]));
429 CheckRadioButton (hwnd, IDC0_PROTTELNET, IDC0_PROTSSH,
430 cfg.protocol==PROT_SSH ? IDC0_PROTSSH : IDC0_PROTTELNET);
431 CheckDlgButton (hwnd, IDC0_CLOSEEXIT, cfg.close_on_exit);
434 switch (LOWORD(wParam)) {
435 case IDC0_PROTTELNET:
437 if (HIWORD(wParam) == BN_CLICKED ||
438 HIWORD(wParam) == BN_DOUBLECLICKED) {
439 int i = IsDlgButtonChecked (hwnd, IDC0_PROTSSH);
440 cfg.protocol = i ? PROT_SSH : PROT_TELNET;
441 if ((cfg.protocol == PROT_SSH && cfg.port == 23) ||
442 (cfg.protocol == PROT_TELNET && cfg.port == 22)) {
443 cfg.port = i ? 22 : 23;
444 SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE);
449 if (HIWORD(wParam) == EN_CHANGE)
450 GetDlgItemText (hwnd, IDC0_HOST, cfg.host,
454 if (HIWORD(wParam) == EN_CHANGE)
455 MyGetDlgItemInt (hwnd, IDC0_PORT, &cfg.port);
458 if (HIWORD(wParam) == BN_CLICKED ||
459 HIWORD(wParam) == BN_DOUBLECLICKED)
460 cfg.close_on_exit = IsDlgButtonChecked (hwnd, IDC0_CLOSEEXIT);
463 if (HIWORD(wParam) == EN_CHANGE)
464 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
468 if (HIWORD(wParam) == BN_CLICKED ||
469 HIWORD(wParam) == BN_DOUBLECLICKED) {
474 GetDlgItemText (hwnd, IDC0_SESSEDIT, str, sizeof(str)-1);
476 int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
482 strcpy (str, sessions[n]);
484 save_settings (str, !!strcmp(str, "Default Settings"));
485 get_sesslist (FALSE);
487 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_RESETCONTENT,
489 for (i = 0; i < nsessions; i++)
490 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING,
491 0, (LPARAM) (sessions[i]));
492 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
498 if (LOWORD(wParam) == IDC0_SESSLOAD &&
499 HIWORD(wParam) != BN_CLICKED &&
500 HIWORD(wParam) != BN_DOUBLECLICKED)
502 if (LOWORD(wParam) == IDC0_SESSLIST &&
503 HIWORD(wParam) != LBN_DBLCLK)
506 int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
512 load_settings (sessions[n],
513 !!strcmp(sessions[n], "Default Settings"));
514 SetDlgItemText (hwnd, IDC0_HOST, cfg.host);
515 SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE);
516 CheckRadioButton (hwnd, IDC0_PROTTELNET, IDC0_PROTSSH,
517 (cfg.protocol==PROT_SSH ? IDC0_PROTSSH :
519 CheckDlgButton (hwnd, IDC0_CLOSEEXIT, cfg.close_on_exit);
520 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
523 if (LOWORD(wParam) == IDC0_SESSLIST) {
525 * A double-click on a saved session should
526 * actually start the session, not just load it.
527 * Unless it's Default Settings or some other
528 * host-less set of saved settings.
531 SendMessage (GetParent(hwnd), WM_COMMAND, IDOK, 0);
535 if (HIWORD(wParam) == BN_CLICKED ||
536 HIWORD(wParam) == BN_DOUBLECLICKED) {
537 int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
539 if (n == LB_ERR || n == 0) {
543 del_session(sessions[n]);
544 get_sesslist (FALSE);
546 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_RESETCONTENT,
548 for (i = 0; i < nsessions; i++)
549 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING,
550 0, (LPARAM) (sessions[i]));
551 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
556 return GeneralPanelProc (hwnd, msg, wParam, lParam);
559 static int CALLBACK KeyboardProc (HWND hwnd, UINT msg,
560 WPARAM wParam, LPARAM lParam) {
563 CheckRadioButton (hwnd, IDC1_DEL008, IDC1_DEL127,
564 cfg.bksp_is_delete ? IDC1_DEL127 : IDC1_DEL008);
565 CheckRadioButton (hwnd, IDC1_HOMETILDE, IDC1_HOMERXVT,
566 cfg.rxvt_homeend ? IDC1_HOMERXVT : IDC1_HOMETILDE);
567 CheckRadioButton (hwnd, IDC1_FUNCTILDE, IDC1_FUNCLINUX,
568 cfg.linux_funkeys ? IDC1_FUNCLINUX : IDC1_FUNCTILDE);
569 CheckRadioButton (hwnd, IDC1_CURNORMAL, IDC1_CURAPPLIC,
570 cfg.app_cursor ? IDC1_CURAPPLIC : IDC1_CURNORMAL);
571 CheckRadioButton (hwnd, IDC1_KPNORMAL, IDC1_KPAPPLIC,
572 cfg.app_keypad ? IDC1_KPAPPLIC : IDC1_KPNORMAL);
575 if (HIWORD(wParam) == BN_CLICKED ||
576 HIWORD(wParam) == BN_DOUBLECLICKED)
577 switch (LOWORD(wParam)) {
580 cfg.bksp_is_delete = IsDlgButtonChecked (hwnd, IDC1_DEL127);
584 cfg.rxvt_homeend = IsDlgButtonChecked (hwnd, IDC1_HOMERXVT);
588 cfg.linux_funkeys = IsDlgButtonChecked (hwnd, IDC1_FUNCLINUX);
592 cfg.app_keypad = IsDlgButtonChecked (hwnd, IDC1_KPAPPLIC);
596 cfg.app_cursor = IsDlgButtonChecked (hwnd, IDC1_CURAPPLIC);
600 return GeneralPanelProc (hwnd, msg, wParam, lParam);
603 static void fmtfont (char *buf) {
604 sprintf (buf, "Font: %s, ", cfg.font);
606 strcat(buf, "bold, ");
607 if (cfg.fontheight == 0)
608 strcat (buf, "default height");
610 sprintf (buf+strlen(buf), "%d-%s",
611 (cfg.fontheight < 0 ? -cfg.fontheight : cfg.fontheight),
612 (cfg.fontheight < 0 ? "pixel" : "point"));
615 static int CALLBACK TerminalProc (HWND hwnd, UINT msg,
616 WPARAM wParam, LPARAM lParam) {
619 char fontstatic[256];
623 CheckDlgButton (hwnd, IDC2_WRAPMODE, cfg.wrap_mode);
624 CheckDlgButton (hwnd, IDC2_WINNAME, cfg.win_name_always);
625 CheckDlgButton (hwnd, IDC2_DECOM, cfg.dec_om);
626 CheckDlgButton (hwnd, IDC2_LFHASCR, cfg.lfhascr);
627 SetDlgItemInt (hwnd, IDC2_ROWSEDIT, cfg.height, FALSE);
628 SetDlgItemInt (hwnd, IDC2_COLSEDIT, cfg.width, FALSE);
629 SetDlgItemInt (hwnd, IDC2_SAVEEDIT, cfg.savelines, FALSE);
630 fmtfont (fontstatic);
631 SetDlgItemText (hwnd, IDC2_FONTSTATIC, fontstatic);
632 CheckRadioButton (hwnd, IDC2_VTXWINDOWS, IDC2_VTPOORMAN,
633 cfg.vtmode == VT_XWINDOWS ? IDC2_VTXWINDOWS :
634 cfg.vtmode == VT_OEMANSI ? IDC2_VTOEMANSI :
635 cfg.vtmode == VT_OEMONLY ? IDC2_VTOEMONLY :
639 switch (LOWORD(wParam)) {
641 if (HIWORD(wParam) == BN_CLICKED ||
642 HIWORD(wParam) == BN_DOUBLECLICKED)
643 cfg.wrap_mode = IsDlgButtonChecked (hwnd, IDC2_WRAPMODE);
646 if (HIWORD(wParam) == BN_CLICKED ||
647 HIWORD(wParam) == BN_DOUBLECLICKED)
648 cfg.win_name_always = IsDlgButtonChecked (hwnd, IDC2_WINNAME);
651 if (HIWORD(wParam) == BN_CLICKED ||
652 HIWORD(wParam) == BN_DOUBLECLICKED)
653 cfg.dec_om = IsDlgButtonChecked (hwnd, IDC2_DECOM);
656 if (HIWORD(wParam) == BN_CLICKED ||
657 HIWORD(wParam) == BN_DOUBLECLICKED)
658 cfg.lfhascr = IsDlgButtonChecked (hwnd, IDC2_LFHASCR);
661 if (HIWORD(wParam) == EN_CHANGE)
662 MyGetDlgItemInt (hwnd, IDC2_ROWSEDIT, &cfg.height);
665 if (HIWORD(wParam) == EN_CHANGE)
666 MyGetDlgItemInt (hwnd, IDC2_COLSEDIT, &cfg.width);
669 if (HIWORD(wParam) == EN_CHANGE)
670 MyGetDlgItemInt (hwnd, IDC2_SAVEEDIT, &cfg.savelines);
672 case IDC2_CHOOSEFONT:
673 lf.lfHeight = cfg.fontheight;
674 lf.lfWidth = lf.lfEscapement = lf.lfOrientation = 0;
675 lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = 0;
676 lf.lfWeight = (cfg.fontisbold ? FW_BOLD : 0);
677 lf.lfCharSet = ANSI_CHARSET;
678 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
679 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
680 lf.lfQuality = DEFAULT_QUALITY;
681 lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
682 strncpy (lf.lfFaceName, cfg.font, sizeof(lf.lfFaceName)-1);
683 lf.lfFaceName[sizeof(lf.lfFaceName)-1] = '\0';
685 cf.lStructSize = sizeof(cf);
688 cf.Flags = CF_FIXEDPITCHONLY | CF_FORCEFONTEXIST |
689 CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
691 if (ChooseFont (&cf)) {
692 strncpy (cfg.font, lf.lfFaceName, sizeof(cfg.font)-1);
693 cfg.font[sizeof(cfg.font)-1] = '\0';
694 cfg.fontisbold = (lf.lfWeight == FW_BOLD);
695 cfg.fontheight = lf.lfHeight;
696 fmtfont (fontstatic);
697 SetDlgItemText (hwnd, IDC2_FONTSTATIC, fontstatic);
700 case IDC2_VTXWINDOWS:
705 (IsDlgButtonChecked (hwnd, IDC2_VTXWINDOWS) ? VT_XWINDOWS :
706 IsDlgButtonChecked (hwnd, IDC2_VTOEMANSI) ? VT_OEMANSI :
707 IsDlgButtonChecked (hwnd, IDC2_VTOEMONLY) ? VT_OEMONLY :
713 return GeneralPanelProc (hwnd, msg, wParam, lParam);
716 static int CALLBACK TelnetProc (HWND hwnd, UINT msg,
717 WPARAM wParam, LPARAM lParam) {
722 SetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype);
723 SetDlgItemText (hwnd, IDC3_TSEDIT, cfg.termspeed);
724 SetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username);
726 char *p = cfg.environmt;
728 SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_ADDSTRING, 0,
733 CheckRadioButton (hwnd, IDC3_EMBSD, IDC3_EMRFC,
734 cfg.rfc_environ ? IDC3_EMRFC : IDC3_EMBSD);
737 switch (LOWORD(wParam)) {
739 if (HIWORD(wParam) == EN_CHANGE)
740 GetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype,
741 sizeof(cfg.termtype)-1);
744 if (HIWORD(wParam) == EN_CHANGE)
745 GetDlgItemText (hwnd, IDC3_TSEDIT, cfg.termspeed,
746 sizeof(cfg.termspeed)-1);
749 if (HIWORD(wParam) == EN_CHANGE)
750 GetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username,
751 sizeof(cfg.username)-1);
755 cfg.rfc_environ = IsDlgButtonChecked (hwnd, IDC3_EMRFC);
758 if (HIWORD(wParam) == BN_CLICKED ||
759 HIWORD(wParam) == BN_DOUBLECLICKED) {
760 char str[sizeof(cfg.environmt)];
762 GetDlgItemText (hwnd, IDC3_VAREDIT, str, sizeof(str)-1);
767 p = str + strlen(str);
769 GetDlgItemText (hwnd, IDC3_VALEDIT, p, sizeof(str)-1-(p-str));
779 if ((p-cfg.environmt) + strlen(str) + 2 < sizeof(cfg.environmt)) {
781 p[strlen(str)+1] = '\0';
782 SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_ADDSTRING,
784 SetDlgItemText (hwnd, IDC3_VAREDIT, "");
785 SetDlgItemText (hwnd, IDC3_VALEDIT, "");
787 MessageBox(hwnd, "Environment too big", "PuTTY Error",
788 MB_OK | MB_ICONERROR);
793 if (HIWORD(wParam) != BN_CLICKED &&
794 HIWORD(wParam) != BN_DOUBLECLICKED)
796 i = SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_GETCURSEL, 0, 0);
802 SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_DELETESTRING,
829 return GeneralPanelProc (hwnd, msg, wParam, lParam);
832 static int CALLBACK SshProc (HWND hwnd, UINT msg,
833 WPARAM wParam, LPARAM lParam) {
836 SetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype);
837 SetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username);
838 CheckDlgButton (hwnd, IDC3_NOPTY, cfg.nopty);
841 switch (LOWORD(wParam)) {
843 if (HIWORD(wParam) == EN_CHANGE)
844 GetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype,
845 sizeof(cfg.termtype)-1);
848 if (HIWORD(wParam) == EN_CHANGE)
849 GetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username,
850 sizeof(cfg.username)-1);
853 if (HIWORD(wParam) == BN_CLICKED ||
854 HIWORD(wParam) == BN_DOUBLECLICKED)
855 cfg.nopty = IsDlgButtonChecked (hwnd, IDC3_NOPTY);
860 return GeneralPanelProc (hwnd, msg, wParam, lParam);
863 static int CALLBACK SelectionProc (HWND hwnd, UINT msg,
864 WPARAM wParam, LPARAM lParam) {
869 CheckRadioButton (hwnd, IDC4_MBWINDOWS, IDC4_MBXTERM,
870 cfg.mouse_is_xterm ? IDC4_MBXTERM : IDC4_MBWINDOWS);
872 static int tabs[4] = {25, 61, 96, 128};
873 SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_SETTABSTOPS, 4,
876 for (i=0; i<256; i++) {
878 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
879 (i>=0x21 && i != 0x7F) ? i : ' ',
881 SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_ADDSTRING, 0,
886 switch (LOWORD(wParam)) {
889 cfg.mouse_is_xterm = IsDlgButtonChecked (hwnd, IDC4_MBXTERM);
895 int n = GetDlgItemInt (hwnd, IDC4_CCEDIT, &ok, FALSE);
900 for (i=0; i<256; i++)
901 if (SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_GETSEL,
905 SendDlgItemMessage (hwnd, IDC4_CCLIST,
906 LB_DELETESTRING, i, 0);
907 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
908 (i>=0x21 && i != 0x7F) ? i : ' ',
910 SendDlgItemMessage (hwnd, IDC4_CCLIST,
920 return GeneralPanelProc (hwnd, msg, wParam, lParam);
923 static int CALLBACK ColourProc (HWND hwnd, UINT msg,
924 WPARAM wParam, LPARAM lParam) {
925 static const char *const colours[] = {
926 "Default Foreground", "Default Bold Foreground",
927 "Default Background", "Default Bold Background",
928 "Cursor Text", "Cursor Colour",
929 "ANSI Black", "ANSI Black Bold",
930 "ANSI Red", "ANSI Red Bold",
931 "ANSI Green", "ANSI Green Bold",
932 "ANSI Yellow", "ANSI Yellow Bold",
933 "ANSI Blue", "ANSI Blue Bold",
934 "ANSI Magenta", "ANSI Magenta Bold",
935 "ANSI Cyan", "ANSI Cyan Bold",
936 "ANSI White", "ANSI White Bold"
938 static const int permanent[] = {
939 TRUE, FALSE, TRUE, FALSE, TRUE, TRUE,
940 TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE,
941 TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE
945 CheckDlgButton (hwnd, IDC5_BOLDCOLOUR, cfg.bold_colour);
946 CheckDlgButton (hwnd, IDC5_PALETTE, cfg.try_palette);
950 if (cfg.bold_colour || permanent[i])
951 SendDlgItemMessage (hwnd, IDC5_LIST, LB_ADDSTRING, 0,
952 (LPARAM) colours[i]);
954 SendDlgItemMessage (hwnd, IDC5_LIST, LB_SETCURSEL, 0, 0);
955 SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[0][0], FALSE);
956 SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[0][1], FALSE);
957 SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[0][2], FALSE);
960 switch (LOWORD(wParam)) {
961 case IDC5_BOLDCOLOUR:
962 if (HIWORD(wParam) == BN_CLICKED ||
963 HIWORD(wParam) == BN_DOUBLECLICKED) {
965 cfg.bold_colour = IsDlgButtonChecked (hwnd, IDC5_BOLDCOLOUR);
966 n = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCOUNT, 0, 0);
967 if (cfg.bold_colour && n!=22) {
970 SendDlgItemMessage (hwnd, IDC5_LIST,
972 (LPARAM) colours[i]);
973 } else if (!cfg.bold_colour && n!=12) {
976 SendDlgItemMessage (hwnd, IDC5_LIST,
977 LB_DELETESTRING, i, 0);
982 if (HIWORD(wParam) == BN_CLICKED ||
983 HIWORD(wParam) == BN_DOUBLECLICKED)
984 cfg.try_palette = IsDlgButtonChecked (hwnd, IDC5_PALETTE);
987 if (HIWORD(wParam) == LBN_DBLCLK ||
988 HIWORD(wParam) == LBN_SELCHANGE) {
989 int i = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCURSEL,
991 if (!cfg.bold_colour)
992 i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
993 SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[i][0], FALSE);
994 SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[i][1], FALSE);
995 SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[i][2], FALSE);
999 if (HIWORD(wParam) == BN_CLICKED ||
1000 HIWORD(wParam) == BN_DOUBLECLICKED) {
1001 static CHOOSECOLOR cc;
1002 static DWORD custom[16] = {0}; /* zero initialisers */
1003 int i = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCURSEL,
1005 if (!cfg.bold_colour)
1006 i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
1007 cc.lStructSize = sizeof(cc);
1008 cc.hwndOwner = hwnd;
1009 cc.hInstance = hinst;
1010 cc.lpCustColors = custom;
1011 cc.rgbResult = RGB (cfg.colours[i][0], cfg.colours[i][1],
1013 cc.Flags = CC_FULLOPEN | CC_RGBINIT;
1014 if (ChooseColor(&cc)) {
1016 (unsigned char) (cc.rgbResult & 0xFF);
1018 (unsigned char) (cc.rgbResult >> 8) & 0xFF;
1020 (unsigned char) (cc.rgbResult >> 16) & 0xFF;
1021 SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[i][0],
1023 SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[i][1],
1025 SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[i][2],
1033 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1036 static DTemplate negot, main, reconf, panels[NPANELS];
1037 static DLGPROC panelproc[NPANELS] = {
1038 ConnectionProc, KeyboardProc, TerminalProc,
1039 TelnetProc, SshProc, SelectionProc, ColourProc
1041 static char *panelids[NPANELS] = {
1042 MAKEINTRESOURCE(IDD_PANEL0),
1043 MAKEINTRESOURCE(IDD_PANEL1),
1044 MAKEINTRESOURCE(IDD_PANEL2),
1045 MAKEINTRESOURCE(IDD_PANEL3),
1046 MAKEINTRESOURCE(IDD_PANEL35),
1047 MAKEINTRESOURCE(IDD_PANEL4),
1048 MAKEINTRESOURCE(IDD_PANEL5)
1050 static char *names[NPANELS] = {
1051 "Connection", "Keyboard", "Terminal", "Telnet", "SSH", "Selection", "Colours"
1054 static int mainp[MAIN_NPANELS] = { 0, 1, 2, 3, 4, 5, 6 };
1055 static int reconfp[RECONF_NPANELS] = { 1, 2, 5, 6 };
1057 static int GenericMainDlgProc (HWND hwnd, UINT msg,
1058 WPARAM wParam, LPARAM lParam,
1059 int npanels, int *panelnums, HWND *page) {
1064 { /* centre the window */
1067 hw = GetDesktopWindow();
1068 if (GetWindowRect (hw, &rs) && GetWindowRect (hwnd, &rd))
1069 MoveWindow (hwnd, (rs.right + rs.left + rd.left - rd.right)/2,
1070 (rs.bottom + rs.top + rd.top - rd.bottom)/2,
1071 rd.right-rd.left, rd.bottom-rd.top, TRUE);
1074 { /* initialise the tab control */
1078 hw = GetDlgItem (hwnd, IDC_TAB);
1079 for (i=0; i<npanels; i++) {
1080 tab.mask = TCIF_TEXT;
1081 tab.pszText = names[panelnums[i]];
1082 TabCtrl_InsertItem (hw, i, &tab);
1084 /* *page = CreateDialogIndirect (hinst, panels[panelnums[0]].temp,
1085 hwnd, panelproc[panelnums[0]]);*/
1086 *page = CreateDialog (hinst, panelids[panelnums[0]],
1087 hwnd, panelproc[panelnums[0]]);
1088 SetWindowLong (*page, GWL_EXSTYLE,
1089 GetWindowLong (*page, GWL_EXSTYLE) |
1090 WS_EX_CONTROLPARENT);
1095 if (LOWORD(wParam) == IDC_TAB &&
1096 ((LPNMHDR)lParam)->code == TCN_SELCHANGE) {
1097 int i = TabCtrl_GetCurSel(((LPNMHDR)lParam)->hwndFrom);
1099 DestroyWindow (*page);
1100 /* *page = CreateDialogIndirect (hinst, panels[panelnums[i]].temp,
1101 hwnd, panelproc[panelnums[i]]);*/
1102 *page = CreateDialog (hinst, panelids[panelnums[i]],
1103 hwnd, panelproc[panelnums[i]]);
1104 SetWindowLong (*page, GWL_EXSTYLE,
1105 GetWindowLong (*page, GWL_EXSTYLE) |
1106 WS_EX_CONTROLPARENT);
1107 SetFocus (((LPNMHDR)lParam)->hwndFrom); /* ensure focus stays */
1111 /* case WM_CTLCOLORDLG: */
1112 /* return (int) GetStockObject (LTGRAY_BRUSH); */
1114 switch (LOWORD(wParam)) {
1117 EndDialog (hwnd, 1);
1122 EndDialog (hwnd, 0);
1127 EndDialog (hwnd, 0);
1133 static int CALLBACK MainDlgProc (HWND hwnd, UINT msg,
1134 WPARAM wParam, LPARAM lParam) {
1139 static HWND page = NULL;
1141 if (msg == WM_COMMAND && LOWORD(wParam) == IDOK) {
1144 * If the Connection panel is active and the Session List
1145 * box is selected, we treat a press of Open to have an
1146 * implicit press of Load preceding it.
1148 hw = GetDlgItem (hwnd, IDC_TAB);
1149 i = TabCtrl_GetCurSel(hw);
1150 if (panelproc[mainp[i]] == ConnectionProc &&
1151 page && implicit_load_ok) {
1152 SendMessage (page, WM_COMMAND,
1153 MAKELONG(IDC0_SESSLOAD, BN_CLICKED), 0);
1157 if (msg == WM_COMMAND && LOWORD(wParam) == IDC_ABOUT) {
1158 EnableWindow(hwnd, 0);
1159 DialogBox(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
1160 GetParent(hwnd), AboutProc);
1161 EnableWindow(hwnd, 1);
1163 return GenericMainDlgProc (hwnd, msg, wParam, lParam,
1164 MAIN_NPANELS, mainp, &page);
1167 static int CALLBACK ReconfDlgProc (HWND hwnd, UINT msg,
1168 WPARAM wParam, LPARAM lParam) {
1170 return GenericMainDlgProc (hwnd, msg, wParam, lParam,
1171 RECONF_NPANELS, reconfp, &page);
1174 static void get_sesslist(int allocate) {
1175 static char *buffer;
1176 int buflen, bufsize, i, ret;
1177 char otherbuf[2048];
1182 if (RegCreateKey(HKEY_CURRENT_USER,
1183 puttystr, &subkey1) != ERROR_SUCCESS)
1186 buflen = bufsize = 0;
1190 ret = RegEnumKey(subkey1, i++, otherbuf, sizeof(otherbuf));
1191 if (ret == ERROR_SUCCESS) {
1192 bufsize = buflen + 2048;
1193 buffer = srealloc(buffer, bufsize);
1194 unmungestr(otherbuf, buffer+buflen);
1195 buflen += strlen(buffer+buflen)+1;
1197 } while (ret == ERROR_SUCCESS);
1198 buffer = srealloc(buffer, buflen+1);
1199 buffer[buflen] = '\0';
1202 nsessions = 1; /* "Default Settings" counts as one */
1204 if (strcmp(p, "Default Settings"))
1210 sessions = smalloc(nsessions * sizeof(char *));
1211 sessions[0] = "Default Settings";
1215 if (strcmp(p, "Default Settings"))
1226 int do_config (void) {
1230 ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_MAINBOX), NULL, MainDlgProc);
1231 get_sesslist(FALSE);
1236 int do_reconfig (HWND hwnd) {
1240 backup_cfg = cfg; /* structure copy */
1241 ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_RECONF), hwnd, ReconfDlgProc);
1243 cfg = backup_cfg; /* structure copy */
1247 void do_defaults (char *session) {
1249 load_settings (session, TRUE);
1251 load_settings ("Default Settings", FALSE);
1254 void lognegot (char *string) {
1255 if (nnegots >= negsize) {
1257 negots = srealloc (negots, negsize * sizeof(*negots));
1259 negots[nnegots] = smalloc(1+strlen(string));
1260 strcpy (negots[nnegots], string);
1263 SendDlgItemMessage (logbox, IDN_LIST, LB_ADDSTRING,
1267 void shownegot (HWND hwnd) {
1269 logbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_LOGBOX),
1271 ShowWindow (logbox, SW_SHOWNORMAL);
1275 void showabout (HWND hwnd) {
1277 abtbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
1279 ShowWindow (abtbox, SW_SHOWNORMAL);
1283 void verify_ssh_host_key(char *host, struct RSAKey *key) {
1284 char *keystr, *otherstr, *mungedhost;
1289 * Format the key into a string.
1291 len = rsastr_len(key);
1292 keystr = malloc(len);
1294 fatalbox("Out of memory");
1295 rsastr_fmt(keystr, key);
1298 * Now read a saved key in from the registry and see what it
1301 otherstr = malloc(len);
1302 mungedhost = malloc(3*strlen(host)+1);
1303 if (!otherstr || !mungedhost)
1304 fatalbox("Out of memory");
1306 mungestr(host, mungedhost);
1308 if (RegCreateKey(HKEY_CURRENT_USER, PUTTY_REG_POS "\\SshHostKeys",
1309 &rkey) != ERROR_SUCCESS) {
1310 if (MessageBox(NULL, "PuTTY was unable to open the host key cache\n"
1311 "in the registry. There is thus no way to tell\n"
1312 "if the remote host is what you think it is.\n"
1313 "Connect anyway?", "PuTTY Problem",
1314 MB_ICONWARNING | MB_YESNO) == IDNO)
1317 DWORD readlen = len;
1321 ret = RegQueryValueEx(rkey, mungedhost, NULL,
1322 &type, otherstr, &readlen);
1324 if (ret == ERROR_MORE_DATA ||
1325 (ret == ERROR_SUCCESS && type == REG_SZ &&
1326 strcmp(otherstr, keystr))) {
1327 if (MessageBox(NULL,
1328 "This host's host key is different from the\n"
1329 "one cached in the registry! Someone may be\n"
1330 "impersonating this host for malicious reasons;\n"
1331 "alternatively, the host key may have changed\n"
1332 "due to sloppy system administration.\n"
1333 "Replace key in registry and connect?",
1334 "PuTTY: Security Warning",
1335 MB_ICONWARNING | MB_YESNO) == IDNO)
1337 RegSetValueEx(rkey, mungedhost, 0, REG_SZ, keystr,
1339 } else if (ret != ERROR_SUCCESS || type != REG_SZ) {
1340 if (MessageBox(NULL,
1341 "This host's host key is not cached in the\n"
1342 "registry. Do you want to add it to the cache\n"
1343 "and carry on connecting?",
1345 MB_ICONWARNING | MB_YESNO) == IDNO)
1347 RegSetValueEx(rkey, mungedhost, 0, REG_SZ, keystr,