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.environ)], *p, *q;
143 if (c == '=' || c == ',' || c == '\\')
153 wpps (sesskey, "Environment", buf);
155 wpps (sesskey, "UserName", cfg.username);
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, "WinNameAlways", cfg.win_name_always);
166 wppi (sesskey, "TermWidth", cfg.width);
167 wppi (sesskey, "TermHeight", cfg.height);
168 wpps (sesskey, "Font", cfg.font);
169 wppi (sesskey, "FontIsBold", cfg.fontisbold);
170 wppi (sesskey, "FontHeight", cfg.fontheight);
171 wppi (sesskey, "FontVTMode", cfg.vtmode);
172 wppi (sesskey, "TryPalette", cfg.try_palette);
173 wppi (sesskey, "BoldAsColour", cfg.bold_colour);
174 for (i=0; i<22; i++) {
175 char buf[20], buf2[30];
176 sprintf(buf, "Colour%d", i);
177 sprintf(buf2, "%d,%d,%d", cfg.colours[i][0],
178 cfg.colours[i][1], cfg.colours[i][2]);
179 wpps (sesskey, buf, buf2);
181 wppi (sesskey, "MouseIsXterm", cfg.mouse_is_xterm);
182 for (i=0; i<256; i+=32) {
183 char buf[20], buf2[256];
185 sprintf(buf, "Wordness%d", i);
187 for (j=i; j<i+32; j++) {
188 sprintf(buf2+strlen(buf2), "%s%d",
189 (*buf2 ? "," : ""), cfg.wordness[j]);
191 wpps (sesskey, buf, buf2);
194 RegCloseKey(sesskey);
197 static void del_session (char *section) {
201 if (RegOpenKey(HKEY_CURRENT_USER, puttystr, &subkey1) != ERROR_SUCCESS)
204 p = malloc(3*strlen(section)+1);
205 mungestr(section, p);
206 RegDeleteKey(subkey1, p);
209 RegCloseKey(subkey1);
212 static void load_settings (char *section, int do_host) {
214 HKEY subkey1, sesskey;
217 p = malloc(3*strlen(section)+1);
218 mungestr(section, p);
220 if (RegOpenKey(HKEY_CURRENT_USER, puttystr, &subkey1) != ERROR_SUCCESS ||
221 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.environ)], *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, "RFCEnviron", 0, &cfg.rfc_environ);
268 gppi (sesskey, "BackspaceIsDelete", 1, &cfg.bksp_is_delete);
269 gppi (sesskey, "RXVTHomeEnd", 0, &cfg.rxvt_homeend);
270 gppi (sesskey, "LinuxFunctionKeys", 0, &cfg.linux_funkeys);
271 gppi (sesskey, "ApplicationCursorKeys", 0, &cfg.app_cursor);
272 gppi (sesskey, "ApplicationKeypad", 0, &cfg.app_keypad);
273 gppi (sesskey, "ScrollbackLines", 200, &cfg.savelines);
274 gppi (sesskey, "DECOriginMode", 0, &cfg.dec_om);
275 gppi (sesskey, "AutoWrapMode", 1, &cfg.wrap_mode);
276 gppi (sesskey, "WinNameAlways", 0, &cfg.win_name_always);
277 gppi (sesskey, "TermWidth", 80, &cfg.width);
278 gppi (sesskey, "TermHeight", 24, &cfg.height);
279 gpps (sesskey, "Font", "Courier", cfg.font, sizeof(cfg.font));
280 gppi (sesskey, "FontIsBold", 0, &cfg.fontisbold);
281 gppi (sesskey, "FontHeight", 10, &cfg.fontheight);
282 gppi (sesskey, "FontVTMode", VT_POORMAN, &cfg.vtmode);
283 gppi (sesskey, "TryPalette", 0, &cfg.try_palette);
284 gppi (sesskey, "BoldAsColour", 1, &cfg.bold_colour);
285 for (i=0; i<22; i++) {
286 static char *defaults[] = {
287 "187,187,187", "255,255,255", "0,0,0", "85,85,85", "0,0,0",
288 "0,255,0", "0,0,0", "85,85,85", "187,0,0", "255,85,85",
289 "0,187,0", "85,255,85", "187,187,0", "255,255,85", "0,0,187",
290 "85,85,255", "187,0,187", "255,85,255", "0,187,187",
291 "85,255,255", "187,187,187", "255,255,255"
293 char buf[20], buf2[30];
294 sprintf(buf, "Colour%d", i);
295 gpps (sesskey, buf, defaults[i], buf2, sizeof(buf2));
296 sscanf(buf2, "%d,%d,%d", &cfg.colours[i][0],
297 &cfg.colours[i][1], &cfg.colours[i][2]);
299 gppi (sesskey, "MouseIsXterm", 0, &cfg.mouse_is_xterm);
300 for (i=0; i<256; i+=32) {
301 static char *defaults[] = {
302 "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",
303 "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",
304 "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",
305 "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",
306 "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",
307 "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",
308 "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",
309 "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 char buf[20], buf2[256], *p;
313 sprintf(buf, "Wordness%d", i);
314 gpps (sesskey, buf, defaults[i/32], buf2, sizeof(buf2));
316 for (j=i; j<i+32; j++) {
318 while (*p && *p != ',') p++;
319 if (*p == ',') *p++ = '\0';
320 cfg.wordness[j] = atoi(q);
323 RegCloseKey(sesskey);
326 static void MyGetDlgItemInt (HWND hwnd, int id, int *result) {
329 n = GetDlgItemInt (hwnd, id, &ok, FALSE);
334 static int CALLBACK LogProc (HWND hwnd, UINT msg,
335 WPARAM wParam, LPARAM lParam) {
340 for (i=0; i<nnegots; i++)
341 SendDlgItemMessage (hwnd, IDN_LIST, LB_ADDSTRING,
342 0, (LPARAM)negots[i]);
344 /* case WM_CTLCOLORDLG: */
345 /* return (int) GetStockObject (LTGRAY_BRUSH); */
347 switch (LOWORD(wParam)) {
350 DestroyWindow (hwnd);
356 DestroyWindow (hwnd);
362 static int CALLBACK AboutProc (HWND hwnd, UINT msg,
363 WPARAM wParam, LPARAM lParam) {
367 /* case WM_CTLCOLORDLG: */
368 /* return (int) GetStockObject (LTGRAY_BRUSH); */
369 /* case WM_CTLCOLORSTATIC: */
370 /* SetBkColor ((HDC)wParam, RGB(192,192,192)); */
371 /* return (int) GetStockObject (LTGRAY_BRUSH); */
373 switch (LOWORD(wParam)) {
376 DestroyWindow (hwnd);
379 EnableWindow(hwnd, 0);
380 DialogBox (hinst, MAKEINTRESOURCE(IDD_LICENCEBOX),
382 EnableWindow(hwnd, 1);
388 DestroyWindow (hwnd);
394 static int GeneralPanelProc (HWND hwnd, UINT msg,
395 WPARAM wParam, LPARAM lParam) {
398 SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
400 /* case WM_CTLCOLORDLG: */
401 /* return (int) GetStockObject (LTGRAY_BRUSH); */
402 /* case WM_CTLCOLORSTATIC: */
403 /* case WM_CTLCOLORBTN: */
404 /* SetBkColor ((HDC)wParam, RGB(192,192,192)); */
405 /* return (int) GetStockObject (LTGRAY_BRUSH); */
407 DestroyWindow (hwnd);
413 static int CALLBACK ConnectionProc (HWND hwnd, UINT msg,
414 WPARAM wParam, LPARAM lParam) {
419 SetDlgItemText (hwnd, IDC0_HOST, cfg.host);
420 SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE);
421 for (i = 0; i < nsessions; i++)
422 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING,
423 0, (LPARAM) (sessions[i]));
424 CheckRadioButton (hwnd, IDC0_PROTTELNET, IDC0_PROTSSH,
425 cfg.protocol==PROT_SSH ? IDC0_PROTSSH : IDC0_PROTTELNET);
426 CheckDlgButton (hwnd, IDC0_CLOSEEXIT, cfg.close_on_exit);
429 switch (LOWORD(wParam)) {
430 case IDC0_PROTTELNET:
432 if (HIWORD(wParam) == BN_CLICKED ||
433 HIWORD(wParam) == BN_DOUBLECLICKED) {
434 int i = IsDlgButtonChecked (hwnd, IDC0_PROTSSH);
435 cfg.protocol = i ? PROT_SSH : PROT_TELNET;
436 if ((cfg.protocol == PROT_SSH && cfg.port == 23) ||
437 (cfg.protocol == PROT_TELNET && cfg.port == 22)) {
438 cfg.port = i ? 22 : 23;
439 SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE);
444 if (HIWORD(wParam) == EN_CHANGE)
445 GetDlgItemText (hwnd, IDC0_HOST, cfg.host,
449 if (HIWORD(wParam) == EN_CHANGE)
450 MyGetDlgItemInt (hwnd, IDC0_PORT, &cfg.port);
453 if (HIWORD(wParam) == BN_CLICKED ||
454 HIWORD(wParam) == BN_DOUBLECLICKED)
455 cfg.close_on_exit = IsDlgButtonChecked (hwnd, IDC0_CLOSEEXIT);
458 if (HIWORD(wParam) == EN_CHANGE)
459 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
463 if (HIWORD(wParam) == BN_CLICKED ||
464 HIWORD(wParam) == BN_DOUBLECLICKED) {
469 GetDlgItemText (hwnd, IDC0_SESSEDIT, str, sizeof(str)-1);
471 int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
477 strcpy (str, sessions[n]);
479 save_settings (str, !!strcmp(str, "Default Settings"));
480 get_sesslist (FALSE);
482 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_RESETCONTENT,
484 for (i = 0; i < nsessions; i++)
485 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING,
486 0, (LPARAM) (sessions[i]));
487 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
493 if (LOWORD(wParam) == IDC0_SESSLOAD &&
494 HIWORD(wParam) != BN_CLICKED &&
495 HIWORD(wParam) != BN_DOUBLECLICKED)
497 if (LOWORD(wParam) == IDC0_SESSLIST &&
498 HIWORD(wParam) != LBN_DBLCLK)
501 int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
507 load_settings (sessions[n],
508 !!strcmp(sessions[n], "Default Settings"));
509 SetDlgItemText (hwnd, IDC0_HOST, cfg.host);
510 SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE);
511 CheckRadioButton (hwnd, IDC0_PROTTELNET, IDC0_PROTSSH,
512 (cfg.protocol==PROT_SSH ? IDC0_PROTSSH :
514 CheckDlgButton (hwnd, IDC0_CLOSEEXIT, cfg.close_on_exit);
515 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
518 if (LOWORD(wParam) == IDC0_SESSLIST) {
520 * A double-click on a saved session should
521 * actually start the session, not just load it.
522 * Unless it's Default Settings or some other
523 * host-less set of saved settings.
526 SendMessage (GetParent(hwnd), WM_COMMAND, IDOK, 0);
530 if (HIWORD(wParam) == BN_CLICKED ||
531 HIWORD(wParam) == BN_DOUBLECLICKED) {
532 int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
534 if (n == LB_ERR || n == 0) {
538 del_session(sessions[n]);
539 get_sesslist (FALSE);
541 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_RESETCONTENT,
543 for (i = 0; i < nsessions; i++)
544 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING,
545 0, (LPARAM) (sessions[i]));
546 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
551 return GeneralPanelProc (hwnd, msg, wParam, lParam);
554 static int CALLBACK KeyboardProc (HWND hwnd, UINT msg,
555 WPARAM wParam, LPARAM lParam) {
558 CheckRadioButton (hwnd, IDC1_DEL008, IDC1_DEL127,
559 cfg.bksp_is_delete ? IDC1_DEL127 : IDC1_DEL008);
560 CheckRadioButton (hwnd, IDC1_HOMETILDE, IDC1_HOMERXVT,
561 cfg.rxvt_homeend ? IDC1_HOMERXVT : IDC1_HOMETILDE);
562 CheckRadioButton (hwnd, IDC1_FUNCTILDE, IDC1_FUNCLINUX,
563 cfg.linux_funkeys ? IDC1_FUNCLINUX : IDC1_FUNCTILDE);
564 CheckRadioButton (hwnd, IDC1_CURNORMAL, IDC1_CURAPPLIC,
565 cfg.app_cursor ? IDC1_CURAPPLIC : IDC1_CURNORMAL);
566 CheckRadioButton (hwnd, IDC1_KPNORMAL, IDC1_KPAPPLIC,
567 cfg.app_keypad ? IDC1_KPAPPLIC : IDC1_KPNORMAL);
570 if (HIWORD(wParam) == BN_CLICKED ||
571 HIWORD(wParam) == BN_DOUBLECLICKED)
572 switch (LOWORD(wParam)) {
575 cfg.bksp_is_delete = IsDlgButtonChecked (hwnd, IDC1_DEL127);
579 cfg.rxvt_homeend = IsDlgButtonChecked (hwnd, IDC1_HOMERXVT);
583 cfg.linux_funkeys = IsDlgButtonChecked (hwnd, IDC1_FUNCLINUX);
587 cfg.app_keypad = IsDlgButtonChecked (hwnd, IDC1_KPAPPLIC);
591 cfg.app_cursor = IsDlgButtonChecked (hwnd, IDC1_CURAPPLIC);
595 return GeneralPanelProc (hwnd, msg, wParam, lParam);
598 static void fmtfont (char *buf) {
599 sprintf (buf, "Font: %s, ", cfg.font);
601 strcat(buf, "bold, ");
602 if (cfg.fontheight == 0)
603 strcat (buf, "default height");
605 sprintf (buf+strlen(buf), "%d-%s",
606 (cfg.fontheight < 0 ? -cfg.fontheight : cfg.fontheight),
607 (cfg.fontheight < 0 ? "pixel" : "point"));
610 static int CALLBACK TerminalProc (HWND hwnd, UINT msg,
611 WPARAM wParam, LPARAM lParam) {
614 char fontstatic[256];
618 CheckDlgButton (hwnd, IDC2_WRAPMODE, cfg.wrap_mode);
619 CheckDlgButton (hwnd, IDC2_WINNAME, cfg.win_name_always);
620 CheckDlgButton (hwnd, IDC2_DECOM, cfg.dec_om);
621 SetDlgItemInt (hwnd, IDC2_ROWSEDIT, cfg.height, FALSE);
622 SetDlgItemInt (hwnd, IDC2_COLSEDIT, cfg.width, FALSE);
623 SetDlgItemInt (hwnd, IDC2_SAVEEDIT, cfg.savelines, FALSE);
624 fmtfont (fontstatic);
625 SetDlgItemText (hwnd, IDC2_FONTSTATIC, fontstatic);
626 CheckRadioButton (hwnd, IDC2_VTXWINDOWS, IDC2_VTPOORMAN,
627 cfg.vtmode == VT_XWINDOWS ? IDC2_VTXWINDOWS :
628 cfg.vtmode == VT_OEMANSI ? IDC2_VTOEMANSI :
629 cfg.vtmode == VT_OEMONLY ? IDC2_VTOEMONLY :
633 switch (LOWORD(wParam)) {
635 if (HIWORD(wParam) == BN_CLICKED ||
636 HIWORD(wParam) == BN_DOUBLECLICKED)
637 cfg.wrap_mode = IsDlgButtonChecked (hwnd, IDC2_WRAPMODE);
640 if (HIWORD(wParam) == BN_CLICKED ||
641 HIWORD(wParam) == BN_DOUBLECLICKED)
642 cfg.win_name_always = IsDlgButtonChecked (hwnd, IDC2_WINNAME);
645 if (HIWORD(wParam) == BN_CLICKED ||
646 HIWORD(wParam) == BN_DOUBLECLICKED)
647 cfg.dec_om = IsDlgButtonChecked (hwnd, IDC2_DECOM);
650 if (HIWORD(wParam) == EN_CHANGE)
651 MyGetDlgItemInt (hwnd, IDC2_ROWSEDIT, &cfg.height);
654 if (HIWORD(wParam) == EN_CHANGE)
655 MyGetDlgItemInt (hwnd, IDC2_COLSEDIT, &cfg.width);
658 if (HIWORD(wParam) == EN_CHANGE)
659 MyGetDlgItemInt (hwnd, IDC2_SAVEEDIT, &cfg.savelines);
661 case IDC2_CHOOSEFONT:
662 lf.lfHeight = cfg.fontheight;
663 lf.lfWidth = lf.lfEscapement = lf.lfOrientation = 0;
664 lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = 0;
665 lf.lfWeight = (cfg.fontisbold ? FW_BOLD : 0);
666 lf.lfCharSet = ANSI_CHARSET;
667 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
668 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
669 lf.lfQuality = DEFAULT_QUALITY;
670 lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
671 strncpy (lf.lfFaceName, cfg.font, sizeof(lf.lfFaceName)-1);
672 lf.lfFaceName[sizeof(lf.lfFaceName)-1] = '\0';
674 cf.lStructSize = sizeof(cf);
677 cf.Flags = CF_FIXEDPITCHONLY | CF_FORCEFONTEXIST |
678 CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
680 if (ChooseFont (&cf)) {
681 strncpy (cfg.font, lf.lfFaceName, sizeof(cfg.font)-1);
682 cfg.font[sizeof(cfg.font)-1] = '\0';
683 cfg.fontisbold = (lf.lfWeight == FW_BOLD);
684 cfg.fontheight = lf.lfHeight;
685 fmtfont (fontstatic);
686 SetDlgItemText (hwnd, IDC2_FONTSTATIC, fontstatic);
689 case IDC2_VTXWINDOWS:
694 (IsDlgButtonChecked (hwnd, IDC2_VTXWINDOWS) ? VT_XWINDOWS :
695 IsDlgButtonChecked (hwnd, IDC2_VTOEMANSI) ? VT_OEMANSI :
696 IsDlgButtonChecked (hwnd, IDC2_VTOEMONLY) ? VT_OEMONLY :
702 return GeneralPanelProc (hwnd, msg, wParam, lParam);
705 static int CALLBACK TelnetProc (HWND hwnd, UINT msg,
706 WPARAM wParam, LPARAM lParam) {
711 SetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype);
712 SetDlgItemText (hwnd, IDC3_TSEDIT, cfg.termspeed);
713 SetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username);
715 char *p = cfg.environ;
717 SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_ADDSTRING, 0,
722 CheckRadioButton (hwnd, IDC3_EMBSD, IDC3_EMRFC,
723 cfg.rfc_environ ? IDC3_EMRFC : IDC3_EMBSD);
726 switch (LOWORD(wParam)) {
728 if (HIWORD(wParam) == EN_CHANGE)
729 GetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype,
730 sizeof(cfg.termtype)-1);
733 if (HIWORD(wParam) == EN_CHANGE)
734 GetDlgItemText (hwnd, IDC3_TSEDIT, cfg.termspeed,
735 sizeof(cfg.termspeed)-1);
738 if (HIWORD(wParam) == EN_CHANGE)
739 GetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username,
740 sizeof(cfg.username)-1);
744 cfg.rfc_environ = IsDlgButtonChecked (hwnd, IDC3_EMRFC);
747 if (HIWORD(wParam) == BN_CLICKED ||
748 HIWORD(wParam) == BN_DOUBLECLICKED) {
749 char str[sizeof(cfg.environ)];
751 GetDlgItemText (hwnd, IDC3_VAREDIT, str, sizeof(str)-1);
756 p = str + strlen(str);
758 GetDlgItemText (hwnd, IDC3_VALEDIT, p, sizeof(str)-1-(p-str));
768 if ((p-cfg.environ) + strlen(str) + 2 < sizeof(cfg.environ)) {
770 p[strlen(str)+1] = '\0';
771 SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_ADDSTRING,
773 SetDlgItemText (hwnd, IDC3_VAREDIT, "");
774 SetDlgItemText (hwnd, IDC3_VALEDIT, "");
776 MessageBox(hwnd, "Environment too big", "PuTTY Error",
777 MB_OK | MB_ICONERROR);
782 if (HIWORD(wParam) != BN_CLICKED &&
783 HIWORD(wParam) != BN_DOUBLECLICKED)
785 i = SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_GETCURSEL, 0, 0);
791 SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_DELETESTRING,
818 return GeneralPanelProc (hwnd, msg, wParam, lParam);
821 static int CALLBACK SshProc (HWND hwnd, UINT msg,
822 WPARAM wParam, LPARAM lParam) {
825 SetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype);
826 SetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username);
829 switch (LOWORD(wParam)) {
831 if (HIWORD(wParam) == EN_CHANGE)
832 GetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype,
833 sizeof(cfg.termtype)-1);
836 if (HIWORD(wParam) == EN_CHANGE)
837 GetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username,
838 sizeof(cfg.username)-1);
843 return GeneralPanelProc (hwnd, msg, wParam, lParam);
846 static int CALLBACK SelectionProc (HWND hwnd, UINT msg,
847 WPARAM wParam, LPARAM lParam) {
852 CheckRadioButton (hwnd, IDC4_MBWINDOWS, IDC4_MBXTERM,
853 cfg.mouse_is_xterm ? IDC4_MBXTERM : IDC4_MBWINDOWS);
855 static int tabs[4] = {25, 61, 96, 128};
856 SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_SETTABSTOPS, 4,
859 for (i=0; i<256; i++) {
861 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
862 (i>=0x21 && i != 0x7F) ? i : ' ',
864 SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_ADDSTRING, 0,
869 switch (LOWORD(wParam)) {
872 cfg.mouse_is_xterm = IsDlgButtonChecked (hwnd, IDC4_MBXTERM);
878 int n = GetDlgItemInt (hwnd, IDC4_CCEDIT, &ok, FALSE);
883 for (i=0; i<256; i++)
884 if (SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_GETSEL,
888 SendDlgItemMessage (hwnd, IDC4_CCLIST,
889 LB_DELETESTRING, i, 0);
890 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
891 (i>=0x21 && i != 0x7F) ? i : ' ',
893 SendDlgItemMessage (hwnd, IDC4_CCLIST,
903 return GeneralPanelProc (hwnd, msg, wParam, lParam);
906 static int CALLBACK ColourProc (HWND hwnd, UINT msg,
907 WPARAM wParam, LPARAM lParam) {
908 static const char *const colours[] = {
909 "Default Foreground", "Default Bold Foreground",
910 "Default Background", "Default Bold Background",
911 "Cursor Text", "Cursor Colour",
912 "ANSI Black", "ANSI Black Bold",
913 "ANSI Red", "ANSI Red Bold",
914 "ANSI Green", "ANSI Green Bold",
915 "ANSI Yellow", "ANSI Yellow Bold",
916 "ANSI Blue", "ANSI Blue Bold",
917 "ANSI Magenta", "ANSI Magenta Bold",
918 "ANSI Cyan", "ANSI Cyan Bold",
919 "ANSI White", "ANSI White Bold"
921 static const int permanent[] = {
922 TRUE, FALSE, TRUE, FALSE, TRUE, TRUE,
923 TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE,
924 TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE
928 CheckDlgButton (hwnd, IDC5_BOLDCOLOUR, cfg.bold_colour);
929 CheckDlgButton (hwnd, IDC5_PALETTE, cfg.try_palette);
933 if (cfg.bold_colour || permanent[i])
934 SendDlgItemMessage (hwnd, IDC5_LIST, LB_ADDSTRING, 0,
935 (LPARAM) colours[i]);
937 SendDlgItemMessage (hwnd, IDC5_LIST, LB_SETCURSEL, 0, 0);
938 SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[0][0], FALSE);
939 SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[0][1], FALSE);
940 SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[0][2], FALSE);
943 switch (LOWORD(wParam)) {
944 case IDC5_BOLDCOLOUR:
945 if (HIWORD(wParam) == BN_CLICKED ||
946 HIWORD(wParam) == BN_DOUBLECLICKED) {
948 cfg.bold_colour = IsDlgButtonChecked (hwnd, IDC5_BOLDCOLOUR);
949 n = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCOUNT, 0, 0);
950 if (cfg.bold_colour && n!=22) {
953 SendDlgItemMessage (hwnd, IDC5_LIST,
955 (LPARAM) colours[i]);
956 } else if (!cfg.bold_colour && n!=12) {
959 SendDlgItemMessage (hwnd, IDC5_LIST,
960 LB_DELETESTRING, i, 0);
965 if (HIWORD(wParam) == BN_CLICKED ||
966 HIWORD(wParam) == BN_DOUBLECLICKED)
967 cfg.try_palette = IsDlgButtonChecked (hwnd, IDC5_PALETTE);
970 if (HIWORD(wParam) == LBN_DBLCLK ||
971 HIWORD(wParam) == LBN_SELCHANGE) {
972 int i = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCURSEL,
974 if (!cfg.bold_colour)
975 i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
976 SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[i][0], FALSE);
977 SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[i][1], FALSE);
978 SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[i][2], FALSE);
982 if (HIWORD(wParam) == BN_CLICKED ||
983 HIWORD(wParam) == BN_DOUBLECLICKED) {
984 static CHOOSECOLOR cc;
985 static DWORD custom[16] = {0}; /* zero initialisers */
986 int i = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCURSEL,
988 if (!cfg.bold_colour)
989 i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
990 cc.lStructSize = sizeof(cc);
992 cc.hInstance = hinst;
993 cc.lpCustColors = custom;
994 cc.rgbResult = RGB (cfg.colours[i][0], cfg.colours[i][1],
996 cc.Flags = CC_FULLOPEN | CC_RGBINIT;
997 if (ChooseColor(&cc)) {
999 (unsigned char) (cc.rgbResult & 0xFF);
1001 (unsigned char) (cc.rgbResult >> 8) & 0xFF;
1003 (unsigned char) (cc.rgbResult >> 16) & 0xFF;
1004 SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[i][0],
1006 SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[i][1],
1008 SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[i][2],
1016 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1019 static DTemplate negot, main, reconf, panels[NPANELS];
1020 static DLGPROC panelproc[NPANELS] = {
1021 ConnectionProc, KeyboardProc, TerminalProc,
1022 TelnetProc, SshProc, SelectionProc, ColourProc
1024 static char *panelids[NPANELS] = {
1025 MAKEINTRESOURCE(IDD_PANEL0),
1026 MAKEINTRESOURCE(IDD_PANEL1),
1027 MAKEINTRESOURCE(IDD_PANEL2),
1028 MAKEINTRESOURCE(IDD_PANEL3),
1029 MAKEINTRESOURCE(IDD_PANEL35),
1030 MAKEINTRESOURCE(IDD_PANEL4),
1031 MAKEINTRESOURCE(IDD_PANEL5)
1033 static char *names[NPANELS] = {
1034 "Connection", "Keyboard", "Terminal", "Telnet", "SSH", "Selection", "Colours"
1037 static int mainp[MAIN_NPANELS] = { 0, 1, 2, 3, 4, 5, 6 };
1038 static int reconfp[RECONF_NPANELS] = { 1, 2, 5, 6 };
1040 static int GenericMainDlgProc (HWND hwnd, UINT msg,
1041 WPARAM wParam, LPARAM lParam,
1042 int npanels, int *panelnums, HWND *page) {
1047 { /* centre the window */
1050 hw = GetDesktopWindow();
1051 if (GetWindowRect (hw, &rs) && GetWindowRect (hwnd, &rd))
1052 MoveWindow (hwnd, (rs.right + rs.left + rd.left - rd.right)/2,
1053 (rs.bottom + rs.top + rd.top - rd.bottom)/2,
1054 rd.right-rd.left, rd.bottom-rd.top, TRUE);
1057 { /* initialise the tab control */
1061 hw = GetDlgItem (hwnd, IDC_TAB);
1062 for (i=0; i<npanels; i++) {
1063 tab.mask = TCIF_TEXT;
1064 tab.pszText = names[panelnums[i]];
1065 TabCtrl_InsertItem (hw, i, &tab);
1067 /* *page = CreateDialogIndirect (hinst, panels[panelnums[0]].temp,
1068 hwnd, panelproc[panelnums[0]]);*/
1069 *page = CreateDialog (hinst, panelids[panelnums[0]],
1070 hwnd, panelproc[panelnums[0]]);
1071 SetWindowLong (*page, GWL_EXSTYLE,
1072 GetWindowLong (*page, GWL_EXSTYLE) |
1073 WS_EX_CONTROLPARENT);
1078 if (LOWORD(wParam) == IDC_TAB &&
1079 ((LPNMHDR)lParam)->code == TCN_SELCHANGE) {
1080 int i = TabCtrl_GetCurSel(((LPNMHDR)lParam)->hwndFrom);
1082 DestroyWindow (*page);
1083 /* *page = CreateDialogIndirect (hinst, panels[panelnums[i]].temp,
1084 hwnd, panelproc[panelnums[i]]);*/
1085 *page = CreateDialog (hinst, panelids[panelnums[i]],
1086 hwnd, panelproc[panelnums[i]]);
1087 SetWindowLong (*page, GWL_EXSTYLE,
1088 GetWindowLong (*page, GWL_EXSTYLE) |
1089 WS_EX_CONTROLPARENT);
1090 SetFocus (((LPNMHDR)lParam)->hwndFrom); /* ensure focus stays */
1094 /* case WM_CTLCOLORDLG: */
1095 /* return (int) GetStockObject (LTGRAY_BRUSH); */
1097 switch (LOWORD(wParam)) {
1100 EndDialog (hwnd, 1);
1105 EndDialog (hwnd, 0);
1110 EndDialog (hwnd, 0);
1116 static int CALLBACK MainDlgProc (HWND hwnd, UINT msg,
1117 WPARAM wParam, LPARAM lParam) {
1122 static HWND page = NULL;
1124 if (msg == WM_COMMAND && LOWORD(wParam) == IDOK) {
1127 * If the Connection panel is active and the Session List
1128 * box is selected, we treat a press of Open to have an
1129 * implicit press of Load preceding it.
1131 hw = GetDlgItem (hwnd, IDC_TAB);
1132 i = TabCtrl_GetCurSel(hw);
1133 if (panelproc[mainp[i]] == ConnectionProc &&
1134 page && implicit_load_ok) {
1135 SendMessage (page, WM_COMMAND,
1136 MAKELONG(IDC0_SESSLOAD, BN_CLICKED), 0);
1140 if (msg == WM_COMMAND && LOWORD(wParam) == IDC_ABOUT) {
1141 EnableWindow(hwnd, 0);
1142 DialogBox(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
1143 GetParent(hwnd), AboutProc);
1144 EnableWindow(hwnd, 1);
1146 return GenericMainDlgProc (hwnd, msg, wParam, lParam,
1147 MAIN_NPANELS, mainp, &page);
1150 static int CALLBACK ReconfDlgProc (HWND hwnd, UINT msg,
1151 WPARAM wParam, LPARAM lParam) {
1153 return GenericMainDlgProc (hwnd, msg, wParam, lParam,
1154 RECONF_NPANELS, reconfp, &page);
1157 static void get_sesslist(int allocate) {
1158 static char *buffer;
1159 int buflen, bufsize, i, ret;
1160 char otherbuf[2048];
1165 if (RegCreateKey(HKEY_CURRENT_USER,
1166 puttystr, &subkey1) != ERROR_SUCCESS)
1169 buflen = bufsize = 0;
1173 ret = RegEnumKey(subkey1, i++, otherbuf, sizeof(otherbuf));
1174 if (ret == ERROR_SUCCESS) {
1175 bufsize = buflen + 2048;
1176 buffer = srealloc(buffer, bufsize);
1177 unmungestr(otherbuf, buffer+buflen);
1178 buflen += strlen(buffer+buflen)+1;
1180 } while (ret == ERROR_SUCCESS);
1181 buffer = srealloc(buffer, buflen+1);
1182 buffer[buflen] = '\0';
1185 nsessions = 1; /* "Default Settings" counts as one */
1187 if (strcmp(p, "Default Settings"))
1193 sessions = smalloc(nsessions * sizeof(char *));
1194 sessions[0] = "Default Settings";
1198 if (strcmp(p, "Default Settings"))
1209 int do_config (void) {
1213 ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_MAINBOX), NULL, MainDlgProc);
1214 get_sesslist(FALSE);
1219 int do_reconfig (HWND hwnd) {
1223 backup_cfg = cfg; /* structure copy */
1224 ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_RECONF), hwnd, ReconfDlgProc);
1226 cfg = backup_cfg; /* structure copy */
1230 void do_defaults (char *session) {
1232 load_settings (session, TRUE);
1234 load_settings ("Default Settings", FALSE);
1237 void lognegot (char *string) {
1238 if (nnegots >= negsize) {
1240 negots = srealloc (negots, negsize * sizeof(*negots));
1242 negots[nnegots] = smalloc(1+strlen(string));
1243 strcpy (negots[nnegots], string);
1246 SendDlgItemMessage (logbox, IDN_LIST, LB_ADDSTRING,
1250 void shownegot (HWND hwnd) {
1252 logbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_LOGBOX),
1254 ShowWindow (logbox, SW_SHOWNORMAL);
1258 void showabout (HWND hwnd) {
1260 abtbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
1262 ShowWindow (abtbox, SW_SHOWNORMAL);
1266 void verify_ssh_host_key(char *host, struct RSAKey *key) {
1267 char *keystr, *otherstr, *mungedhost;
1272 * Format the key into a string.
1274 len = rsastr_len(key);
1275 keystr = malloc(len);
1277 fatalbox("Out of memory");
1278 rsastr_fmt(keystr, key);
1281 * Now read a saved key in from the registry and see what it
1284 otherstr = malloc(len);
1285 mungedhost = malloc(3*strlen(host)+1);
1286 if (!otherstr || !mungedhost)
1287 fatalbox("Out of memory");
1289 mungestr(host, mungedhost);
1291 if (RegCreateKey(HKEY_CURRENT_USER, PUTTY_REG_POS "\\SshHostKeys",
1292 &rkey) != ERROR_SUCCESS) {
1293 if (MessageBox(NULL, "PuTTY was unable to open the host key cache\n"
1294 "in the registry. There is thus no way to tell\n"
1295 "if the remote host is what you think it is.\n"
1296 "Connect anyway?", "PuTTY Problem",
1297 MB_ICONWARNING | MB_YESNO) == IDNO)
1300 DWORD readlen = len;
1304 ret = RegQueryValueEx(rkey, mungedhost, NULL,
1305 &type, otherstr, &readlen);
1307 if (ret == ERROR_MORE_DATA ||
1308 (ret == ERROR_SUCCESS && type == REG_SZ &&
1309 strcmp(otherstr, keystr))) {
1310 if (MessageBox(NULL,
1311 "This host's host key is different from the\n"
1312 "one cached in the registry! Someone may be\n"
1313 "impersonating this host for malicious reasons;\n"
1314 "alternatively, the host key may have changed\n"
1315 "due to sloppy system administration.\n"
1316 "Replace key in registry and connect?",
1317 "PuTTY: Security Warning",
1318 MB_ICONWARNING | MB_YESNO) == IDNO)
1320 RegSetValueEx(rkey, mungedhost, 0, REG_SZ, keystr,
1322 } else if (ret != ERROR_SUCCESS || type != REG_SZ) {
1323 if (MessageBox(NULL,
1324 "This host's host key is not cached in the\n"
1325 "registry. Do you want to add it to the cache\n"
1326 "and carry on connecting?",
1328 MB_ICONWARNING | MB_YESNO) == IDNO)
1330 RegSetValueEx(rkey, mungedhost, 0, REG_SZ, keystr,