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) {
123 RegCloseKey(subkey1);
125 wppi (sesskey, "Present", 1);
127 wpps (sesskey, "HostName", cfg.host);
128 wppi (sesskey, "PortNumber", cfg.port);
129 wpps (sesskey, "Protocol",
130 cfg.protocol == PROT_SSH ? "ssh" : "telnet");
132 wppi (sesskey, "CloseOnExit", !!cfg.close_on_exit);
133 wpps (sesskey, "TerminalType", cfg.termtype);
134 wpps (sesskey, "TerminalSpeed", cfg.termspeed);
136 char buf[2*sizeof(cfg.environmt)], *p, *q;
142 if (c == '=' || c == ',' || c == '\\')
152 wpps (sesskey, "Environment", buf);
154 wpps (sesskey, "UserName", cfg.username);
155 wppi (sesskey, "NoPTY", cfg.nopty);
156 wppi (sesskey, "RFCEnviron", cfg.rfc_environ);
157 wppi (sesskey, "BackspaceIsDelete", cfg.bksp_is_delete);
158 wppi (sesskey, "RXVTHomeEnd", cfg.rxvt_homeend);
159 wppi (sesskey, "LinuxFunctionKeys", cfg.linux_funkeys);
160 wppi (sesskey, "ApplicationCursorKeys", cfg.app_cursor);
161 wppi (sesskey, "ApplicationKeypad", cfg.app_keypad);
162 wppi (sesskey, "ScrollbackLines", cfg.savelines);
163 wppi (sesskey, "DECOriginMode", cfg.dec_om);
164 wppi (sesskey, "AutoWrapMode", cfg.wrap_mode);
165 wppi (sesskey, "LFImpliesCR", cfg.lfhascr);
166 wppi (sesskey, "WinNameAlways", cfg.win_name_always);
167 wppi (sesskey, "TermWidth", cfg.width);
168 wppi (sesskey, "TermHeight", cfg.height);
169 wpps (sesskey, "Font", cfg.font);
170 wppi (sesskey, "FontIsBold", cfg.fontisbold);
171 wppi (sesskey, "FontHeight", cfg.fontheight);
172 wppi (sesskey, "FontVTMode", cfg.vtmode);
173 wppi (sesskey, "TryPalette", cfg.try_palette);
174 wppi (sesskey, "BoldAsColour", cfg.bold_colour);
175 for (i=0; i<22; i++) {
176 char buf[20], buf2[30];
177 sprintf(buf, "Colour%d", i);
178 sprintf(buf2, "%d,%d,%d", cfg.colours[i][0],
179 cfg.colours[i][1], cfg.colours[i][2]);
180 wpps (sesskey, buf, buf2);
182 wppi (sesskey, "MouseIsXterm", cfg.mouse_is_xterm);
183 for (i=0; i<256; i+=32) {
184 char buf[20], buf2[256];
186 sprintf(buf, "Wordness%d", i);
188 for (j=i; j<i+32; j++) {
189 sprintf(buf2+strlen(buf2), "%s%d",
190 (*buf2 ? "," : ""), cfg.wordness[j]);
192 wpps (sesskey, buf, buf2);
195 RegCloseKey(sesskey);
198 static void del_session (char *section) {
202 if (RegOpenKey(HKEY_CURRENT_USER, puttystr, &subkey1) != ERROR_SUCCESS)
205 p = malloc(3*strlen(section)+1);
206 mungestr(section, p);
207 RegDeleteKey(subkey1, p);
210 RegCloseKey(subkey1);
213 static void load_settings (char *section, int do_host) {
215 HKEY subkey1, sesskey;
218 p = malloc(3*strlen(section)+1);
219 mungestr(section, p);
221 if (RegOpenKey(HKEY_CURRENT_USER, puttystr, &subkey1) != ERROR_SUCCESS ||
222 RegOpenKey(subkey1, p, &sesskey) != ERROR_SUCCESS) {
227 RegCloseKey(subkey1);
231 gpps (sesskey, "HostName", "", cfg.host, sizeof(cfg.host));
232 gppi (sesskey, "PortNumber", 23, &cfg.port);
233 gpps (sesskey, "Protocol", "telnet", prot, 10);
234 if (!strcmp(prot, "ssh"))
235 cfg.protocol = PROT_SSH;
237 cfg.protocol = PROT_TELNET;
242 gppi (sesskey, "CloseOnExit", 1, &cfg.close_on_exit);
243 gpps (sesskey, "TerminalType", "xterm", cfg.termtype,
244 sizeof(cfg.termtype));
245 gpps (sesskey, "TerminalSpeed", "38400,38400", cfg.termspeed,
246 sizeof(cfg.termspeed));
248 char buf[2*sizeof(cfg.environmt)], *p, *q;
249 gpps (sesskey, "Environment", "", buf, sizeof(buf));
253 while (*p && *p != ',') {
266 gpps (sesskey, "UserName", "", cfg.username, sizeof(cfg.username));
267 gppi (sesskey, "NoPTY", 0, &cfg.nopty);
268 gppi (sesskey, "RFCEnviron", 0, &cfg.rfc_environ);
269 gppi (sesskey, "BackspaceIsDelete", 1, &cfg.bksp_is_delete);
270 gppi (sesskey, "RXVTHomeEnd", 0, &cfg.rxvt_homeend);
271 gppi (sesskey, "LinuxFunctionKeys", 0, &cfg.linux_funkeys);
272 gppi (sesskey, "ApplicationCursorKeys", 0, &cfg.app_cursor);
273 gppi (sesskey, "ApplicationKeypad", 0, &cfg.app_keypad);
274 gppi (sesskey, "ScrollbackLines", 200, &cfg.savelines);
275 gppi (sesskey, "DECOriginMode", 0, &cfg.dec_om);
276 gppi (sesskey, "AutoWrapMode", 1, &cfg.wrap_mode);
277 gppi (sesskey, "LFImpliesCR", 0, &cfg.lfhascr);
278 gppi (sesskey, "WinNameAlways", 0, &cfg.win_name_always);
279 gppi (sesskey, "TermWidth", 80, &cfg.width);
280 gppi (sesskey, "TermHeight", 24, &cfg.height);
281 gpps (sesskey, "Font", "Courier", cfg.font, sizeof(cfg.font));
282 gppi (sesskey, "FontIsBold", 0, &cfg.fontisbold);
283 gppi (sesskey, "FontHeight", 10, &cfg.fontheight);
284 gppi (sesskey, "FontVTMode", VT_POORMAN, &cfg.vtmode);
285 gppi (sesskey, "TryPalette", 0, &cfg.try_palette);
286 gppi (sesskey, "BoldAsColour", 1, &cfg.bold_colour);
287 for (i=0; i<22; i++) {
288 static char *defaults[] = {
289 "187,187,187", "255,255,255", "0,0,0", "85,85,85", "0,0,0",
290 "0,255,0", "0,0,0", "85,85,85", "187,0,0", "255,85,85",
291 "0,187,0", "85,255,85", "187,187,0", "255,255,85", "0,0,187",
292 "85,85,255", "187,0,187", "255,85,255", "0,187,187",
293 "85,255,255", "187,187,187", "255,255,255"
295 char buf[20], buf2[30];
296 sprintf(buf, "Colour%d", i);
297 gpps (sesskey, buf, defaults[i], buf2, sizeof(buf2));
298 sscanf(buf2, "%d,%d,%d", &cfg.colours[i][0],
299 &cfg.colours[i][1], &cfg.colours[i][2]);
301 gppi (sesskey, "MouseIsXterm", 0, &cfg.mouse_is_xterm);
302 for (i=0; i<256; i+=32) {
303 static char *defaults[] = {
304 "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",
305 "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",
306 "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",
307 "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",
308 "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",
309 "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",
310 "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",
311 "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 char buf[20], buf2[256], *p;
315 sprintf(buf, "Wordness%d", i);
316 gpps (sesskey, buf, defaults[i/32], buf2, sizeof(buf2));
318 for (j=i; j<i+32; j++) {
320 while (*p && *p != ',') p++;
321 if (*p == ',') *p++ = '\0';
322 cfg.wordness[j] = atoi(q);
325 RegCloseKey(sesskey);
328 static void MyGetDlgItemInt (HWND hwnd, int id, int *result) {
331 n = GetDlgItemInt (hwnd, id, &ok, FALSE);
336 static int CALLBACK LogProc (HWND hwnd, UINT msg,
337 WPARAM wParam, LPARAM lParam) {
342 for (i=0; i<nnegots; i++)
343 SendDlgItemMessage (hwnd, IDN_LIST, LB_ADDSTRING,
344 0, (LPARAM)negots[i]);
346 /* case WM_CTLCOLORDLG: */
347 /* return (int) GetStockObject (LTGRAY_BRUSH); */
349 switch (LOWORD(wParam)) {
352 DestroyWindow (hwnd);
358 DestroyWindow (hwnd);
364 static int CALLBACK AboutProc (HWND hwnd, UINT msg,
365 WPARAM wParam, LPARAM lParam) {
368 SetDlgItemText (hwnd, IDA_VERSION, ver);
370 /* case WM_CTLCOLORDLG: */
371 /* return (int) GetStockObject (LTGRAY_BRUSH); */
372 /* case WM_CTLCOLORSTATIC: */
373 /* SetBkColor ((HDC)wParam, RGB(192,192,192)); */
374 /* return (int) GetStockObject (LTGRAY_BRUSH); */
376 switch (LOWORD(wParam)) {
379 DestroyWindow (hwnd);
382 EnableWindow(hwnd, 0);
383 DialogBox (hinst, MAKEINTRESOURCE(IDD_LICENCEBOX),
385 EnableWindow(hwnd, 1);
391 DestroyWindow (hwnd);
397 static int GeneralPanelProc (HWND hwnd, UINT msg,
398 WPARAM wParam, LPARAM lParam) {
401 SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
403 /* case WM_CTLCOLORDLG: */
404 /* return (int) GetStockObject (LTGRAY_BRUSH); */
405 /* case WM_CTLCOLORSTATIC: */
406 /* case WM_CTLCOLORBTN: */
407 /* SetBkColor ((HDC)wParam, RGB(192,192,192)); */
408 /* return (int) GetStockObject (LTGRAY_BRUSH); */
410 DestroyWindow (hwnd);
416 static int CALLBACK ConnectionProc (HWND hwnd, UINT msg,
417 WPARAM wParam, LPARAM lParam) {
422 SetDlgItemText (hwnd, IDC0_HOST, cfg.host);
423 SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE);
424 for (i = 0; i < nsessions; i++)
425 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING,
426 0, (LPARAM) (sessions[i]));
427 CheckRadioButton (hwnd, IDC0_PROTTELNET, IDC0_PROTSSH,
428 cfg.protocol==PROT_SSH ? IDC0_PROTSSH : IDC0_PROTTELNET);
429 CheckDlgButton (hwnd, IDC0_CLOSEEXIT, cfg.close_on_exit);
432 switch (LOWORD(wParam)) {
433 case IDC0_PROTTELNET:
435 if (HIWORD(wParam) == BN_CLICKED ||
436 HIWORD(wParam) == BN_DOUBLECLICKED) {
437 int i = IsDlgButtonChecked (hwnd, IDC0_PROTSSH);
438 cfg.protocol = i ? PROT_SSH : PROT_TELNET;
439 if ((cfg.protocol == PROT_SSH && cfg.port == 23) ||
440 (cfg.protocol == PROT_TELNET && cfg.port == 22)) {
441 cfg.port = i ? 22 : 23;
442 SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE);
447 if (HIWORD(wParam) == EN_CHANGE)
448 GetDlgItemText (hwnd, IDC0_HOST, cfg.host,
452 if (HIWORD(wParam) == EN_CHANGE)
453 MyGetDlgItemInt (hwnd, IDC0_PORT, &cfg.port);
456 if (HIWORD(wParam) == BN_CLICKED ||
457 HIWORD(wParam) == BN_DOUBLECLICKED)
458 cfg.close_on_exit = IsDlgButtonChecked (hwnd, IDC0_CLOSEEXIT);
461 if (HIWORD(wParam) == EN_CHANGE)
462 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
466 if (HIWORD(wParam) == BN_CLICKED ||
467 HIWORD(wParam) == BN_DOUBLECLICKED) {
472 GetDlgItemText (hwnd, IDC0_SESSEDIT, str, sizeof(str)-1);
474 int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
480 strcpy (str, sessions[n]);
482 save_settings (str, !!strcmp(str, "Default Settings"));
483 get_sesslist (FALSE);
485 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_RESETCONTENT,
487 for (i = 0; i < nsessions; i++)
488 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING,
489 0, (LPARAM) (sessions[i]));
490 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
496 if (LOWORD(wParam) == IDC0_SESSLOAD &&
497 HIWORD(wParam) != BN_CLICKED &&
498 HIWORD(wParam) != BN_DOUBLECLICKED)
500 if (LOWORD(wParam) == IDC0_SESSLIST &&
501 HIWORD(wParam) != LBN_DBLCLK)
504 int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
510 load_settings (sessions[n],
511 !!strcmp(sessions[n], "Default Settings"));
512 SetDlgItemText (hwnd, IDC0_HOST, cfg.host);
513 SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE);
514 CheckRadioButton (hwnd, IDC0_PROTTELNET, IDC0_PROTSSH,
515 (cfg.protocol==PROT_SSH ? IDC0_PROTSSH :
517 CheckDlgButton (hwnd, IDC0_CLOSEEXIT, cfg.close_on_exit);
518 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
521 if (LOWORD(wParam) == IDC0_SESSLIST) {
523 * A double-click on a saved session should
524 * actually start the session, not just load it.
525 * Unless it's Default Settings or some other
526 * host-less set of saved settings.
529 SendMessage (GetParent(hwnd), WM_COMMAND, IDOK, 0);
533 if (HIWORD(wParam) == BN_CLICKED ||
534 HIWORD(wParam) == BN_DOUBLECLICKED) {
535 int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
537 if (n == LB_ERR || n == 0) {
541 del_session(sessions[n]);
542 get_sesslist (FALSE);
544 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_RESETCONTENT,
546 for (i = 0; i < nsessions; i++)
547 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING,
548 0, (LPARAM) (sessions[i]));
549 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
554 return GeneralPanelProc (hwnd, msg, wParam, lParam);
557 static int CALLBACK KeyboardProc (HWND hwnd, UINT msg,
558 WPARAM wParam, LPARAM lParam) {
561 CheckRadioButton (hwnd, IDC1_DEL008, IDC1_DEL127,
562 cfg.bksp_is_delete ? IDC1_DEL127 : IDC1_DEL008);
563 CheckRadioButton (hwnd, IDC1_HOMETILDE, IDC1_HOMERXVT,
564 cfg.rxvt_homeend ? IDC1_HOMERXVT : IDC1_HOMETILDE);
565 CheckRadioButton (hwnd, IDC1_FUNCTILDE, IDC1_FUNCLINUX,
566 cfg.linux_funkeys ? IDC1_FUNCLINUX : IDC1_FUNCTILDE);
567 CheckRadioButton (hwnd, IDC1_CURNORMAL, IDC1_CURAPPLIC,
568 cfg.app_cursor ? IDC1_CURAPPLIC : IDC1_CURNORMAL);
569 CheckRadioButton (hwnd, IDC1_KPNORMAL, IDC1_KPAPPLIC,
570 cfg.app_keypad ? IDC1_KPAPPLIC : IDC1_KPNORMAL);
573 if (HIWORD(wParam) == BN_CLICKED ||
574 HIWORD(wParam) == BN_DOUBLECLICKED)
575 switch (LOWORD(wParam)) {
578 cfg.bksp_is_delete = IsDlgButtonChecked (hwnd, IDC1_DEL127);
582 cfg.rxvt_homeend = IsDlgButtonChecked (hwnd, IDC1_HOMERXVT);
586 cfg.linux_funkeys = IsDlgButtonChecked (hwnd, IDC1_FUNCLINUX);
590 cfg.app_keypad = IsDlgButtonChecked (hwnd, IDC1_KPAPPLIC);
594 cfg.app_cursor = IsDlgButtonChecked (hwnd, IDC1_CURAPPLIC);
598 return GeneralPanelProc (hwnd, msg, wParam, lParam);
601 static void fmtfont (char *buf) {
602 sprintf (buf, "Font: %s, ", cfg.font);
604 strcat(buf, "bold, ");
605 if (cfg.fontheight == 0)
606 strcat (buf, "default height");
608 sprintf (buf+strlen(buf), "%d-%s",
609 (cfg.fontheight < 0 ? -cfg.fontheight : cfg.fontheight),
610 (cfg.fontheight < 0 ? "pixel" : "point"));
613 static int CALLBACK TerminalProc (HWND hwnd, UINT msg,
614 WPARAM wParam, LPARAM lParam) {
617 char fontstatic[256];
621 CheckDlgButton (hwnd, IDC2_WRAPMODE, cfg.wrap_mode);
622 CheckDlgButton (hwnd, IDC2_WINNAME, cfg.win_name_always);
623 CheckDlgButton (hwnd, IDC2_DECOM, cfg.dec_om);
624 CheckDlgButton (hwnd, IDC2_LFHASCR, cfg.lfhascr);
625 SetDlgItemInt (hwnd, IDC2_ROWSEDIT, cfg.height, FALSE);
626 SetDlgItemInt (hwnd, IDC2_COLSEDIT, cfg.width, FALSE);
627 SetDlgItemInt (hwnd, IDC2_SAVEEDIT, cfg.savelines, FALSE);
628 fmtfont (fontstatic);
629 SetDlgItemText (hwnd, IDC2_FONTSTATIC, fontstatic);
630 CheckRadioButton (hwnd, IDC2_VTXWINDOWS, IDC2_VTPOORMAN,
631 cfg.vtmode == VT_XWINDOWS ? IDC2_VTXWINDOWS :
632 cfg.vtmode == VT_OEMANSI ? IDC2_VTOEMANSI :
633 cfg.vtmode == VT_OEMONLY ? IDC2_VTOEMONLY :
637 switch (LOWORD(wParam)) {
639 if (HIWORD(wParam) == BN_CLICKED ||
640 HIWORD(wParam) == BN_DOUBLECLICKED)
641 cfg.wrap_mode = IsDlgButtonChecked (hwnd, IDC2_WRAPMODE);
644 if (HIWORD(wParam) == BN_CLICKED ||
645 HIWORD(wParam) == BN_DOUBLECLICKED)
646 cfg.win_name_always = IsDlgButtonChecked (hwnd, IDC2_WINNAME);
649 if (HIWORD(wParam) == BN_CLICKED ||
650 HIWORD(wParam) == BN_DOUBLECLICKED)
651 cfg.dec_om = IsDlgButtonChecked (hwnd, IDC2_DECOM);
654 if (HIWORD(wParam) == BN_CLICKED ||
655 HIWORD(wParam) == BN_DOUBLECLICKED)
656 cfg.lfhascr = IsDlgButtonChecked (hwnd, IDC2_LFHASCR);
659 if (HIWORD(wParam) == EN_CHANGE)
660 MyGetDlgItemInt (hwnd, IDC2_ROWSEDIT, &cfg.height);
663 if (HIWORD(wParam) == EN_CHANGE)
664 MyGetDlgItemInt (hwnd, IDC2_COLSEDIT, &cfg.width);
667 if (HIWORD(wParam) == EN_CHANGE)
668 MyGetDlgItemInt (hwnd, IDC2_SAVEEDIT, &cfg.savelines);
670 case IDC2_CHOOSEFONT:
671 lf.lfHeight = cfg.fontheight;
672 lf.lfWidth = lf.lfEscapement = lf.lfOrientation = 0;
673 lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = 0;
674 lf.lfWeight = (cfg.fontisbold ? FW_BOLD : 0);
675 lf.lfCharSet = ANSI_CHARSET;
676 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
677 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
678 lf.lfQuality = DEFAULT_QUALITY;
679 lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
680 strncpy (lf.lfFaceName, cfg.font, sizeof(lf.lfFaceName)-1);
681 lf.lfFaceName[sizeof(lf.lfFaceName)-1] = '\0';
683 cf.lStructSize = sizeof(cf);
686 cf.Flags = CF_FIXEDPITCHONLY | CF_FORCEFONTEXIST |
687 CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
689 if (ChooseFont (&cf)) {
690 strncpy (cfg.font, lf.lfFaceName, sizeof(cfg.font)-1);
691 cfg.font[sizeof(cfg.font)-1] = '\0';
692 cfg.fontisbold = (lf.lfWeight == FW_BOLD);
693 cfg.fontheight = lf.lfHeight;
694 fmtfont (fontstatic);
695 SetDlgItemText (hwnd, IDC2_FONTSTATIC, fontstatic);
698 case IDC2_VTXWINDOWS:
703 (IsDlgButtonChecked (hwnd, IDC2_VTXWINDOWS) ? VT_XWINDOWS :
704 IsDlgButtonChecked (hwnd, IDC2_VTOEMANSI) ? VT_OEMANSI :
705 IsDlgButtonChecked (hwnd, IDC2_VTOEMONLY) ? VT_OEMONLY :
711 return GeneralPanelProc (hwnd, msg, wParam, lParam);
714 static int CALLBACK TelnetProc (HWND hwnd, UINT msg,
715 WPARAM wParam, LPARAM lParam) {
720 SetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype);
721 SetDlgItemText (hwnd, IDC3_TSEDIT, cfg.termspeed);
722 SetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username);
724 char *p = cfg.environmt;
726 SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_ADDSTRING, 0,
731 CheckRadioButton (hwnd, IDC3_EMBSD, IDC3_EMRFC,
732 cfg.rfc_environ ? IDC3_EMRFC : IDC3_EMBSD);
735 switch (LOWORD(wParam)) {
737 if (HIWORD(wParam) == EN_CHANGE)
738 GetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype,
739 sizeof(cfg.termtype)-1);
742 if (HIWORD(wParam) == EN_CHANGE)
743 GetDlgItemText (hwnd, IDC3_TSEDIT, cfg.termspeed,
744 sizeof(cfg.termspeed)-1);
747 if (HIWORD(wParam) == EN_CHANGE)
748 GetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username,
749 sizeof(cfg.username)-1);
753 cfg.rfc_environ = IsDlgButtonChecked (hwnd, IDC3_EMRFC);
756 if (HIWORD(wParam) == BN_CLICKED ||
757 HIWORD(wParam) == BN_DOUBLECLICKED) {
758 char str[sizeof(cfg.environmt)];
760 GetDlgItemText (hwnd, IDC3_VAREDIT, str, sizeof(str)-1);
765 p = str + strlen(str);
767 GetDlgItemText (hwnd, IDC3_VALEDIT, p, sizeof(str)-1-(p-str));
777 if ((p-cfg.environmt) + strlen(str) + 2 < sizeof(cfg.environmt)) {
779 p[strlen(str)+1] = '\0';
780 SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_ADDSTRING,
782 SetDlgItemText (hwnd, IDC3_VAREDIT, "");
783 SetDlgItemText (hwnd, IDC3_VALEDIT, "");
785 MessageBox(hwnd, "Environment too big", "PuTTY Error",
786 MB_OK | MB_ICONERROR);
791 if (HIWORD(wParam) != BN_CLICKED &&
792 HIWORD(wParam) != BN_DOUBLECLICKED)
794 i = SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_GETCURSEL, 0, 0);
800 SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_DELETESTRING,
827 return GeneralPanelProc (hwnd, msg, wParam, lParam);
830 static int CALLBACK SshProc (HWND hwnd, UINT msg,
831 WPARAM wParam, LPARAM lParam) {
834 SetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype);
835 SetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username);
836 CheckDlgButton (hwnd, IDC3_NOPTY, cfg.nopty);
839 switch (LOWORD(wParam)) {
841 if (HIWORD(wParam) == EN_CHANGE)
842 GetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype,
843 sizeof(cfg.termtype)-1);
846 if (HIWORD(wParam) == EN_CHANGE)
847 GetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username,
848 sizeof(cfg.username)-1);
851 if (HIWORD(wParam) == BN_CLICKED ||
852 HIWORD(wParam) == BN_DOUBLECLICKED)
853 cfg.nopty = IsDlgButtonChecked (hwnd, IDC3_NOPTY);
858 return GeneralPanelProc (hwnd, msg, wParam, lParam);
861 static int CALLBACK SelectionProc (HWND hwnd, UINT msg,
862 WPARAM wParam, LPARAM lParam) {
867 CheckRadioButton (hwnd, IDC4_MBWINDOWS, IDC4_MBXTERM,
868 cfg.mouse_is_xterm ? IDC4_MBXTERM : IDC4_MBWINDOWS);
870 static int tabs[4] = {25, 61, 96, 128};
871 SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_SETTABSTOPS, 4,
874 for (i=0; i<256; i++) {
876 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
877 (i>=0x21 && i != 0x7F) ? i : ' ',
879 SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_ADDSTRING, 0,
884 switch (LOWORD(wParam)) {
887 cfg.mouse_is_xterm = IsDlgButtonChecked (hwnd, IDC4_MBXTERM);
893 int n = GetDlgItemInt (hwnd, IDC4_CCEDIT, &ok, FALSE);
898 for (i=0; i<256; i++)
899 if (SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_GETSEL,
903 SendDlgItemMessage (hwnd, IDC4_CCLIST,
904 LB_DELETESTRING, i, 0);
905 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
906 (i>=0x21 && i != 0x7F) ? i : ' ',
908 SendDlgItemMessage (hwnd, IDC4_CCLIST,
918 return GeneralPanelProc (hwnd, msg, wParam, lParam);
921 static int CALLBACK ColourProc (HWND hwnd, UINT msg,
922 WPARAM wParam, LPARAM lParam) {
923 static const char *const colours[] = {
924 "Default Foreground", "Default Bold Foreground",
925 "Default Background", "Default Bold Background",
926 "Cursor Text", "Cursor Colour",
927 "ANSI Black", "ANSI Black Bold",
928 "ANSI Red", "ANSI Red Bold",
929 "ANSI Green", "ANSI Green Bold",
930 "ANSI Yellow", "ANSI Yellow Bold",
931 "ANSI Blue", "ANSI Blue Bold",
932 "ANSI Magenta", "ANSI Magenta Bold",
933 "ANSI Cyan", "ANSI Cyan Bold",
934 "ANSI White", "ANSI White Bold"
936 static const int permanent[] = {
937 TRUE, FALSE, TRUE, FALSE, TRUE, TRUE,
938 TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE,
939 TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE
943 CheckDlgButton (hwnd, IDC5_BOLDCOLOUR, cfg.bold_colour);
944 CheckDlgButton (hwnd, IDC5_PALETTE, cfg.try_palette);
948 if (cfg.bold_colour || permanent[i])
949 SendDlgItemMessage (hwnd, IDC5_LIST, LB_ADDSTRING, 0,
950 (LPARAM) colours[i]);
952 SendDlgItemMessage (hwnd, IDC5_LIST, LB_SETCURSEL, 0, 0);
953 SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[0][0], FALSE);
954 SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[0][1], FALSE);
955 SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[0][2], FALSE);
958 switch (LOWORD(wParam)) {
959 case IDC5_BOLDCOLOUR:
960 if (HIWORD(wParam) == BN_CLICKED ||
961 HIWORD(wParam) == BN_DOUBLECLICKED) {
963 cfg.bold_colour = IsDlgButtonChecked (hwnd, IDC5_BOLDCOLOUR);
964 n = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCOUNT, 0, 0);
965 if (cfg.bold_colour && n!=22) {
968 SendDlgItemMessage (hwnd, IDC5_LIST,
970 (LPARAM) colours[i]);
971 } else if (!cfg.bold_colour && n!=12) {
974 SendDlgItemMessage (hwnd, IDC5_LIST,
975 LB_DELETESTRING, i, 0);
980 if (HIWORD(wParam) == BN_CLICKED ||
981 HIWORD(wParam) == BN_DOUBLECLICKED)
982 cfg.try_palette = IsDlgButtonChecked (hwnd, IDC5_PALETTE);
985 if (HIWORD(wParam) == LBN_DBLCLK ||
986 HIWORD(wParam) == LBN_SELCHANGE) {
987 int i = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCURSEL,
989 if (!cfg.bold_colour)
990 i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
991 SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[i][0], FALSE);
992 SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[i][1], FALSE);
993 SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[i][2], FALSE);
997 if (HIWORD(wParam) == BN_CLICKED ||
998 HIWORD(wParam) == BN_DOUBLECLICKED) {
999 static CHOOSECOLOR cc;
1000 static DWORD custom[16] = {0}; /* zero initialisers */
1001 int i = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCURSEL,
1003 if (!cfg.bold_colour)
1004 i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
1005 cc.lStructSize = sizeof(cc);
1006 cc.hwndOwner = hwnd;
1007 cc.hInstance = hinst;
1008 cc.lpCustColors = custom;
1009 cc.rgbResult = RGB (cfg.colours[i][0], cfg.colours[i][1],
1011 cc.Flags = CC_FULLOPEN | CC_RGBINIT;
1012 if (ChooseColor(&cc)) {
1014 (unsigned char) (cc.rgbResult & 0xFF);
1016 (unsigned char) (cc.rgbResult >> 8) & 0xFF;
1018 (unsigned char) (cc.rgbResult >> 16) & 0xFF;
1019 SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[i][0],
1021 SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[i][1],
1023 SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[i][2],
1031 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1034 static DTemplate negot, main, reconf, panels[NPANELS];
1035 static DLGPROC panelproc[NPANELS] = {
1036 ConnectionProc, KeyboardProc, TerminalProc,
1037 TelnetProc, SshProc, SelectionProc, ColourProc
1039 static char *panelids[NPANELS] = {
1040 MAKEINTRESOURCE(IDD_PANEL0),
1041 MAKEINTRESOURCE(IDD_PANEL1),
1042 MAKEINTRESOURCE(IDD_PANEL2),
1043 MAKEINTRESOURCE(IDD_PANEL3),
1044 MAKEINTRESOURCE(IDD_PANEL35),
1045 MAKEINTRESOURCE(IDD_PANEL4),
1046 MAKEINTRESOURCE(IDD_PANEL5)
1048 static char *names[NPANELS] = {
1049 "Connection", "Keyboard", "Terminal", "Telnet", "SSH", "Selection", "Colours"
1052 static int mainp[MAIN_NPANELS] = { 0, 1, 2, 3, 4, 5, 6 };
1053 static int reconfp[RECONF_NPANELS] = { 1, 2, 5, 6 };
1055 static int GenericMainDlgProc (HWND hwnd, UINT msg,
1056 WPARAM wParam, LPARAM lParam,
1057 int npanels, int *panelnums, HWND *page) {
1062 { /* centre the window */
1065 hw = GetDesktopWindow();
1066 if (GetWindowRect (hw, &rs) && GetWindowRect (hwnd, &rd))
1067 MoveWindow (hwnd, (rs.right + rs.left + rd.left - rd.right)/2,
1068 (rs.bottom + rs.top + rd.top - rd.bottom)/2,
1069 rd.right-rd.left, rd.bottom-rd.top, TRUE);
1072 { /* initialise the tab control */
1076 hw = GetDlgItem (hwnd, IDC_TAB);
1077 for (i=0; i<npanels; i++) {
1078 tab.mask = TCIF_TEXT;
1079 tab.pszText = names[panelnums[i]];
1080 TabCtrl_InsertItem (hw, i, &tab);
1082 /* *page = CreateDialogIndirect (hinst, panels[panelnums[0]].temp,
1083 hwnd, panelproc[panelnums[0]]);*/
1084 *page = CreateDialog (hinst, panelids[panelnums[0]],
1085 hwnd, panelproc[panelnums[0]]);
1086 SetWindowLong (*page, GWL_EXSTYLE,
1087 GetWindowLong (*page, GWL_EXSTYLE) |
1088 WS_EX_CONTROLPARENT);
1093 if (LOWORD(wParam) == IDC_TAB &&
1094 ((LPNMHDR)lParam)->code == TCN_SELCHANGE) {
1095 int i = TabCtrl_GetCurSel(((LPNMHDR)lParam)->hwndFrom);
1097 DestroyWindow (*page);
1098 /* *page = CreateDialogIndirect (hinst, panels[panelnums[i]].temp,
1099 hwnd, panelproc[panelnums[i]]);*/
1100 *page = CreateDialog (hinst, panelids[panelnums[i]],
1101 hwnd, panelproc[panelnums[i]]);
1102 SetWindowLong (*page, GWL_EXSTYLE,
1103 GetWindowLong (*page, GWL_EXSTYLE) |
1104 WS_EX_CONTROLPARENT);
1105 SetFocus (((LPNMHDR)lParam)->hwndFrom); /* ensure focus stays */
1109 /* case WM_CTLCOLORDLG: */
1110 /* return (int) GetStockObject (LTGRAY_BRUSH); */
1112 switch (LOWORD(wParam)) {
1115 EndDialog (hwnd, 1);
1120 EndDialog (hwnd, 0);
1125 EndDialog (hwnd, 0);
1131 static int CALLBACK MainDlgProc (HWND hwnd, UINT msg,
1132 WPARAM wParam, LPARAM lParam) {
1137 static HWND page = NULL;
1139 if (msg == WM_COMMAND && LOWORD(wParam) == IDOK) {
1142 * If the Connection panel is active and the Session List
1143 * box is selected, we treat a press of Open to have an
1144 * implicit press of Load preceding it.
1146 hw = GetDlgItem (hwnd, IDC_TAB);
1147 i = TabCtrl_GetCurSel(hw);
1148 if (panelproc[mainp[i]] == ConnectionProc &&
1149 page && implicit_load_ok) {
1150 SendMessage (page, WM_COMMAND,
1151 MAKELONG(IDC0_SESSLOAD, BN_CLICKED), 0);
1155 if (msg == WM_COMMAND && LOWORD(wParam) == IDC_ABOUT) {
1156 EnableWindow(hwnd, 0);
1157 DialogBox(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
1158 GetParent(hwnd), AboutProc);
1159 EnableWindow(hwnd, 1);
1161 return GenericMainDlgProc (hwnd, msg, wParam, lParam,
1162 MAIN_NPANELS, mainp, &page);
1165 static int CALLBACK ReconfDlgProc (HWND hwnd, UINT msg,
1166 WPARAM wParam, LPARAM lParam) {
1168 return GenericMainDlgProc (hwnd, msg, wParam, lParam,
1169 RECONF_NPANELS, reconfp, &page);
1172 static void get_sesslist(int allocate) {
1173 static char *buffer;
1174 int buflen, bufsize, i, ret;
1175 char otherbuf[2048];
1180 if (RegCreateKey(HKEY_CURRENT_USER,
1181 puttystr, &subkey1) != ERROR_SUCCESS)
1184 buflen = bufsize = 0;
1188 ret = RegEnumKey(subkey1, i++, otherbuf, sizeof(otherbuf));
1189 if (ret == ERROR_SUCCESS) {
1190 bufsize = buflen + 2048;
1191 buffer = srealloc(buffer, bufsize);
1192 unmungestr(otherbuf, buffer+buflen);
1193 buflen += strlen(buffer+buflen)+1;
1195 } while (ret == ERROR_SUCCESS);
1196 buffer = srealloc(buffer, buflen+1);
1197 buffer[buflen] = '\0';
1200 nsessions = 1; /* "Default Settings" counts as one */
1202 if (strcmp(p, "Default Settings"))
1208 sessions = smalloc(nsessions * sizeof(char *));
1209 sessions[0] = "Default Settings";
1213 if (strcmp(p, "Default Settings"))
1224 int do_config (void) {
1228 ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_MAINBOX), NULL, MainDlgProc);
1229 get_sesslist(FALSE);
1234 int do_reconfig (HWND hwnd) {
1238 backup_cfg = cfg; /* structure copy */
1239 ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_RECONF), hwnd, ReconfDlgProc);
1241 cfg = backup_cfg; /* structure copy */
1245 void do_defaults (char *session) {
1247 load_settings (session, TRUE);
1249 load_settings ("Default Settings", FALSE);
1252 void lognegot (char *string) {
1253 if (nnegots >= negsize) {
1255 negots = srealloc (negots, negsize * sizeof(*negots));
1257 negots[nnegots] = smalloc(1+strlen(string));
1258 strcpy (negots[nnegots], string);
1261 SendDlgItemMessage (logbox, IDN_LIST, LB_ADDSTRING,
1265 void shownegot (HWND hwnd) {
1267 logbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_LOGBOX),
1269 ShowWindow (logbox, SW_SHOWNORMAL);
1273 void showabout (HWND hwnd) {
1275 abtbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
1277 ShowWindow (abtbox, SW_SHOWNORMAL);
1281 void verify_ssh_host_key(char *host, struct RSAKey *key) {
1282 char *keystr, *otherstr, *mungedhost;
1287 * Format the key into a string.
1289 len = rsastr_len(key);
1290 keystr = malloc(len);
1292 fatalbox("Out of memory");
1293 rsastr_fmt(keystr, key);
1296 * Now read a saved key in from the registry and see what it
1299 otherstr = malloc(len);
1300 mungedhost = malloc(3*strlen(host)+1);
1301 if (!otherstr || !mungedhost)
1302 fatalbox("Out of memory");
1304 mungestr(host, mungedhost);
1306 if (RegCreateKey(HKEY_CURRENT_USER, PUTTY_REG_POS "\\SshHostKeys",
1307 &rkey) != ERROR_SUCCESS) {
1308 if (MessageBox(NULL, "PuTTY was unable to open the host key cache\n"
1309 "in the registry. There is thus no way to tell\n"
1310 "if the remote host is what you think it is.\n"
1311 "Connect anyway?", "PuTTY Problem",
1312 MB_ICONWARNING | MB_YESNO) == IDNO)
1315 DWORD readlen = len;
1319 ret = RegQueryValueEx(rkey, mungedhost, NULL,
1320 &type, otherstr, &readlen);
1322 if (ret == ERROR_MORE_DATA ||
1323 (ret == ERROR_SUCCESS && type == REG_SZ &&
1324 strcmp(otherstr, keystr))) {
1325 if (MessageBox(NULL,
1326 "This host's host key is different from the\n"
1327 "one cached in the registry! Someone may be\n"
1328 "impersonating this host for malicious reasons;\n"
1329 "alternatively, the host key may have changed\n"
1330 "due to sloppy system administration.\n"
1331 "Replace key in registry and connect?",
1332 "PuTTY: Security Warning",
1333 MB_ICONWARNING | MB_YESNO) == IDNO)
1335 RegSetValueEx(rkey, mungedhost, 0, REG_SZ, keystr,
1337 } else if (ret != ERROR_SUCCESS || type != REG_SZ) {
1338 if (MessageBox(NULL,
1339 "This host's host key is not cached in the\n"
1340 "registry. Do you want to add it to the cache\n"
1341 "and carry on connecting?",
1343 MB_ICONWARNING | MB_YESNO) == IDNO)
1345 RegSetValueEx(rkey, mungedhost, 0, REG_SZ, keystr,