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)
98 static HINSTANCE hinst;
100 static char **sessions;
101 static int nsessions;
103 static int readytogo;
105 static void save_settings (char *section, int do_host) {
107 HKEY subkey1, sesskey;
110 p = malloc(3*strlen(section)+1);
111 mungestr(section, p);
113 if (RegCreateKey(HKEY_CURRENT_USER, puttystr, &subkey1)!=ERROR_SUCCESS ||
114 RegCreateKey(subkey1, p, &sesskey) != ERROR_SUCCESS) {
119 RegCloseKey(subkey1);
121 wppi (sesskey, "Present", 1);
123 wpps (sesskey, "HostName", cfg.host);
124 wppi (sesskey, "PortNumber", cfg.port);
125 wpps (sesskey, "Protocol",
126 cfg.protocol == PROT_SSH ? "ssh" : "telnet");
128 wppi (sesskey, "CloseOnExit", !!cfg.close_on_exit);
129 wpps (sesskey, "TerminalType", cfg.termtype);
130 wpps (sesskey, "TerminalSpeed", cfg.termspeed);
132 char buf[2*sizeof(cfg.environmt)], *p, *q;
138 if (c == '=' || c == ',' || c == '\\')
148 wpps (sesskey, "Environment", buf);
150 wpps (sesskey, "UserName", cfg.username);
151 wppi (sesskey, "NoPTY", cfg.nopty);
152 wpps (sesskey, "Cipher", cfg.cipher == CIPHER_BLOWFISH ? "blowfish" :
154 wppi (sesskey, "RFCEnviron", cfg.rfc_environ);
155 wppi (sesskey, "BackspaceIsDelete", cfg.bksp_is_delete);
156 wppi (sesskey, "RXVTHomeEnd", cfg.rxvt_homeend);
157 wppi (sesskey, "LinuxFunctionKeys", cfg.linux_funkeys);
158 wppi (sesskey, "ApplicationCursorKeys", cfg.app_cursor);
159 wppi (sesskey, "ApplicationKeypad", cfg.app_keypad);
160 wppi (sesskey, "ScrollbackLines", cfg.savelines);
161 wppi (sesskey, "DECOriginMode", cfg.dec_om);
162 wppi (sesskey, "AutoWrapMode", cfg.wrap_mode);
163 wppi (sesskey, "LFImpliesCR", cfg.lfhascr);
164 wppi (sesskey, "WinNameAlways", cfg.win_name_always);
165 wppi (sesskey, "TermWidth", cfg.width);
166 wppi (sesskey, "TermHeight", cfg.height);
167 wpps (sesskey, "Font", cfg.font);
168 wppi (sesskey, "FontIsBold", cfg.fontisbold);
169 wppi (sesskey, "FontHeight", cfg.fontheight);
170 wppi (sesskey, "FontVTMode", cfg.vtmode);
171 wppi (sesskey, "TryPalette", cfg.try_palette);
172 wppi (sesskey, "BoldAsColour", cfg.bold_colour);
173 for (i=0; i<22; i++) {
174 char buf[20], buf2[30];
175 sprintf(buf, "Colour%d", i);
176 sprintf(buf2, "%d,%d,%d", cfg.colours[i][0],
177 cfg.colours[i][1], cfg.colours[i][2]);
178 wpps (sesskey, buf, buf2);
180 wppi (sesskey, "MouseIsXterm", cfg.mouse_is_xterm);
181 for (i=0; i<256; i+=32) {
182 char buf[20], buf2[256];
184 sprintf(buf, "Wordness%d", i);
186 for (j=i; j<i+32; j++) {
187 sprintf(buf2+strlen(buf2), "%s%d",
188 (*buf2 ? "," : ""), cfg.wordness[j]);
190 wpps (sesskey, buf, buf2);
193 RegCloseKey(sesskey);
196 static void del_session (char *section) {
200 if (RegOpenKey(HKEY_CURRENT_USER, puttystr, &subkey1) != ERROR_SUCCESS)
203 p = malloc(3*strlen(section)+1);
204 mungestr(section, p);
205 RegDeleteKey(subkey1, p);
208 RegCloseKey(subkey1);
211 static void load_settings (char *section, int do_host) {
213 HKEY subkey1, sesskey;
216 p = malloc(3*strlen(section)+1);
217 mungestr(section, p);
219 if (RegOpenKey(HKEY_CURRENT_USER, puttystr, &subkey1) != ERROR_SUCCESS) {
222 if (RegOpenKey(subkey1, p, &sesskey) != ERROR_SUCCESS) {
225 RegCloseKey(subkey1);
232 gpps (sesskey, "HostName", "", cfg.host, sizeof(cfg.host));
233 gppi (sesskey, "PortNumber", 23, &cfg.port);
234 gpps (sesskey, "Protocol", "telnet", prot, 10);
235 if (!strcmp(prot, "ssh"))
236 cfg.protocol = PROT_SSH;
238 cfg.protocol = PROT_TELNET;
243 gppi (sesskey, "CloseOnExit", 1, &cfg.close_on_exit);
244 gpps (sesskey, "TerminalType", "xterm", cfg.termtype,
245 sizeof(cfg.termtype));
246 gpps (sesskey, "TerminalSpeed", "38400,38400", cfg.termspeed,
247 sizeof(cfg.termspeed));
249 char buf[2*sizeof(cfg.environmt)], *p, *q;
250 gpps (sesskey, "Environment", "", buf, sizeof(buf));
254 while (*p && *p != ',') {
267 gpps (sesskey, "UserName", "", cfg.username, sizeof(cfg.username));
268 gppi (sesskey, "NoPTY", 0, &cfg.nopty);
271 gpps (sesskey, "Cipher", "3des", cipher, 10);
272 if (!strcmp(cipher, "blowfish"))
273 cfg.cipher = CIPHER_BLOWFISH;
275 cfg.cipher = CIPHER_3DES;
277 gppi (sesskey, "RFCEnviron", 0, &cfg.rfc_environ);
278 gppi (sesskey, "BackspaceIsDelete", 1, &cfg.bksp_is_delete);
279 gppi (sesskey, "RXVTHomeEnd", 0, &cfg.rxvt_homeend);
280 gppi (sesskey, "LinuxFunctionKeys", 0, &cfg.linux_funkeys);
281 gppi (sesskey, "ApplicationCursorKeys", 0, &cfg.app_cursor);
282 gppi (sesskey, "ApplicationKeypad", 0, &cfg.app_keypad);
283 gppi (sesskey, "ScrollbackLines", 200, &cfg.savelines);
284 gppi (sesskey, "DECOriginMode", 0, &cfg.dec_om);
285 gppi (sesskey, "AutoWrapMode", 1, &cfg.wrap_mode);
286 gppi (sesskey, "LFImpliesCR", 0, &cfg.lfhascr);
287 gppi (sesskey, "WinNameAlways", 0, &cfg.win_name_always);
288 gppi (sesskey, "TermWidth", 80, &cfg.width);
289 gppi (sesskey, "TermHeight", 24, &cfg.height);
290 gpps (sesskey, "Font", "Courier", cfg.font, sizeof(cfg.font));
291 gppi (sesskey, "FontIsBold", 0, &cfg.fontisbold);
292 gppi (sesskey, "FontHeight", 10, &cfg.fontheight);
293 gppi (sesskey, "FontVTMode", VT_POORMAN, &cfg.vtmode);
294 gppi (sesskey, "TryPalette", 0, &cfg.try_palette);
295 gppi (sesskey, "BoldAsColour", 1, &cfg.bold_colour);
296 for (i=0; i<22; i++) {
297 static char *defaults[] = {
298 "187,187,187", "255,255,255", "0,0,0", "85,85,85", "0,0,0",
299 "0,255,0", "0,0,0", "85,85,85", "187,0,0", "255,85,85",
300 "0,187,0", "85,255,85", "187,187,0", "255,255,85", "0,0,187",
301 "85,85,255", "187,0,187", "255,85,255", "0,187,187",
302 "85,255,255", "187,187,187", "255,255,255"
304 char buf[20], buf2[30];
305 sprintf(buf, "Colour%d", i);
306 gpps (sesskey, buf, defaults[i], buf2, sizeof(buf2));
307 sscanf(buf2, "%d,%d,%d", &cfg.colours[i][0],
308 &cfg.colours[i][1], &cfg.colours[i][2]);
310 gppi (sesskey, "MouseIsXterm", 0, &cfg.mouse_is_xterm);
311 for (i=0; i<256; i+=32) {
312 static char *defaults[] = {
313 "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",
314 "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",
315 "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",
316 "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",
317 "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",
318 "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",
319 "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",
320 "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"
322 char buf[20], buf2[256], *p;
324 sprintf(buf, "Wordness%d", i);
325 gpps (sesskey, buf, defaults[i/32], buf2, sizeof(buf2));
327 for (j=i; j<i+32; j++) {
329 while (*p && *p != ',') p++;
330 if (*p == ',') *p++ = '\0';
331 cfg.wordness[j] = atoi(q);
334 RegCloseKey(sesskey);
337 static void MyGetDlgItemInt (HWND hwnd, int id, int *result) {
340 n = GetDlgItemInt (hwnd, id, &ok, FALSE);
345 static int CALLBACK LogProc (HWND hwnd, UINT msg,
346 WPARAM wParam, LPARAM lParam) {
351 for (i=0; i<nnegots; i++)
352 SendDlgItemMessage (hwnd, IDN_LIST, LB_ADDSTRING,
353 0, (LPARAM)negots[i]);
355 /* case WM_CTLCOLORDLG: */
356 /* return (int) GetStockObject (LTGRAY_BRUSH); */
358 switch (LOWORD(wParam)) {
361 DestroyWindow (hwnd);
367 DestroyWindow (hwnd);
373 static int CALLBACK LicenceProc (HWND hwnd, UINT msg,
374 WPARAM wParam, LPARAM lParam) {
379 switch (LOWORD(wParam)) {
382 DestroyWindow (hwnd);
388 DestroyWindow (hwnd);
394 static int CALLBACK AboutProc (HWND hwnd, UINT msg,
395 WPARAM wParam, LPARAM lParam) {
398 SetDlgItemText (hwnd, IDA_VERSION, ver);
400 /* case WM_CTLCOLORDLG: */
401 /* return (int) GetStockObject (LTGRAY_BRUSH); */
402 /* case WM_CTLCOLORSTATIC: */
403 /* SetBkColor ((HDC)wParam, RGB(192,192,192)); */
404 /* return (int) GetStockObject (LTGRAY_BRUSH); */
406 switch (LOWORD(wParam)) {
409 DestroyWindow (hwnd);
412 EnableWindow(hwnd, 0);
413 DialogBox (hinst, MAKEINTRESOURCE(IDD_LICENCEBOX),
415 EnableWindow(hwnd, 1);
421 DestroyWindow (hwnd);
427 static int GeneralPanelProc (HWND hwnd, UINT msg,
428 WPARAM wParam, LPARAM lParam) {
431 SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
433 /* case WM_CTLCOLORDLG: */
434 /* return (int) GetStockObject (LTGRAY_BRUSH); */
435 /* case WM_CTLCOLORSTATIC: */
436 /* case WM_CTLCOLORBTN: */
437 /* SetBkColor ((HDC)wParam, RGB(192,192,192)); */
438 /* return (int) GetStockObject (LTGRAY_BRUSH); */
440 DestroyWindow (hwnd);
446 static int CALLBACK ConnectionProc (HWND hwnd, UINT msg,
447 WPARAM wParam, LPARAM lParam) {
452 SetDlgItemText (hwnd, IDC0_HOST, cfg.host);
453 SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE);
454 for (i = 0; i < nsessions; i++)
455 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING,
456 0, (LPARAM) (sessions[i]));
457 CheckRadioButton (hwnd, IDC0_PROTTELNET, IDC0_PROTSSH,
458 cfg.protocol==PROT_SSH ? IDC0_PROTSSH : IDC0_PROTTELNET);
459 CheckDlgButton (hwnd, IDC0_CLOSEEXIT, cfg.close_on_exit);
463 * Button release should trigger WM_OK if there was a
464 * previous double click on the session list.
468 SendMessage (GetParent(hwnd), WM_COMMAND, IDOK, 0);
471 switch (LOWORD(wParam)) {
472 case IDC0_PROTTELNET:
474 if (HIWORD(wParam) == BN_CLICKED ||
475 HIWORD(wParam) == BN_DOUBLECLICKED) {
476 int i = IsDlgButtonChecked (hwnd, IDC0_PROTSSH);
477 cfg.protocol = i ? PROT_SSH : PROT_TELNET;
478 if ((cfg.protocol == PROT_SSH && cfg.port == 23) ||
479 (cfg.protocol == PROT_TELNET && cfg.port == 22)) {
480 cfg.port = i ? 22 : 23;
481 SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE);
486 if (HIWORD(wParam) == EN_CHANGE)
487 GetDlgItemText (hwnd, IDC0_HOST, cfg.host,
491 if (HIWORD(wParam) == EN_CHANGE)
492 MyGetDlgItemInt (hwnd, IDC0_PORT, &cfg.port);
495 if (HIWORD(wParam) == BN_CLICKED ||
496 HIWORD(wParam) == BN_DOUBLECLICKED)
497 cfg.close_on_exit = IsDlgButtonChecked (hwnd, IDC0_CLOSEEXIT);
500 if (HIWORD(wParam) == EN_CHANGE)
501 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
505 if (HIWORD(wParam) == BN_CLICKED ||
506 HIWORD(wParam) == BN_DOUBLECLICKED) {
511 GetDlgItemText (hwnd, IDC0_SESSEDIT, str, sizeof(str)-1);
513 int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
519 strcpy (str, sessions[n]);
521 save_settings (str, !!strcmp(str, "Default Settings"));
522 get_sesslist (FALSE);
524 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_RESETCONTENT,
526 for (i = 0; i < nsessions; i++)
527 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING,
528 0, (LPARAM) (sessions[i]));
529 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
535 if (LOWORD(wParam) == IDC0_SESSLOAD &&
536 HIWORD(wParam) != BN_CLICKED &&
537 HIWORD(wParam) != BN_DOUBLECLICKED)
539 if (LOWORD(wParam) == IDC0_SESSLIST &&
540 HIWORD(wParam) != LBN_DBLCLK)
543 int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
549 load_settings (sessions[n],
550 !!strcmp(sessions[n], "Default Settings"));
551 SetDlgItemText (hwnd, IDC0_HOST, cfg.host);
552 SetDlgItemInt (hwnd, IDC0_PORT, cfg.port, FALSE);
553 CheckRadioButton (hwnd, IDC0_PROTTELNET, IDC0_PROTSSH,
554 (cfg.protocol==PROT_SSH ? IDC0_PROTSSH :
556 CheckDlgButton (hwnd, IDC0_CLOSEEXIT, cfg.close_on_exit);
557 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
560 if (LOWORD(wParam) == IDC0_SESSLIST) {
562 * A double-click on a saved session should
563 * actually start the session, not just load it.
564 * Unless it's Default Settings or some other
565 * host-less set of saved settings.
574 if (HIWORD(wParam) == BN_CLICKED ||
575 HIWORD(wParam) == BN_DOUBLECLICKED) {
576 int n = SendDlgItemMessage (hwnd, IDC0_SESSLIST,
578 if (n == LB_ERR || n == 0) {
582 del_session(sessions[n]);
583 get_sesslist (FALSE);
585 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_RESETCONTENT,
587 for (i = 0; i < nsessions; i++)
588 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_ADDSTRING,
589 0, (LPARAM) (sessions[i]));
590 SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
595 return GeneralPanelProc (hwnd, msg, wParam, lParam);
598 static int CALLBACK KeyboardProc (HWND hwnd, UINT msg,
599 WPARAM wParam, LPARAM lParam) {
602 CheckRadioButton (hwnd, IDC1_DEL008, IDC1_DEL127,
603 cfg.bksp_is_delete ? IDC1_DEL127 : IDC1_DEL008);
604 CheckRadioButton (hwnd, IDC1_HOMETILDE, IDC1_HOMERXVT,
605 cfg.rxvt_homeend ? IDC1_HOMERXVT : IDC1_HOMETILDE);
606 CheckRadioButton (hwnd, IDC1_FUNCTILDE, IDC1_FUNCLINUX,
607 cfg.linux_funkeys ? IDC1_FUNCLINUX : IDC1_FUNCTILDE);
608 CheckRadioButton (hwnd, IDC1_CURNORMAL, IDC1_CURAPPLIC,
609 cfg.app_cursor ? IDC1_CURAPPLIC : IDC1_CURNORMAL);
610 CheckRadioButton (hwnd, IDC1_KPNORMAL, IDC1_KPAPPLIC,
611 cfg.app_keypad ? IDC1_KPAPPLIC : IDC1_KPNORMAL);
614 if (HIWORD(wParam) == BN_CLICKED ||
615 HIWORD(wParam) == BN_DOUBLECLICKED)
616 switch (LOWORD(wParam)) {
619 cfg.bksp_is_delete = IsDlgButtonChecked (hwnd, IDC1_DEL127);
623 cfg.rxvt_homeend = IsDlgButtonChecked (hwnd, IDC1_HOMERXVT);
627 cfg.linux_funkeys = IsDlgButtonChecked (hwnd, IDC1_FUNCLINUX);
631 cfg.app_keypad = IsDlgButtonChecked (hwnd, IDC1_KPAPPLIC);
635 cfg.app_cursor = IsDlgButtonChecked (hwnd, IDC1_CURAPPLIC);
639 return GeneralPanelProc (hwnd, msg, wParam, lParam);
642 static void fmtfont (char *buf) {
643 sprintf (buf, "Font: %s, ", cfg.font);
645 strcat(buf, "bold, ");
646 if (cfg.fontheight == 0)
647 strcat (buf, "default height");
649 sprintf (buf+strlen(buf), "%d-%s",
650 (cfg.fontheight < 0 ? -cfg.fontheight : cfg.fontheight),
651 (cfg.fontheight < 0 ? "pixel" : "point"));
654 static int CALLBACK TerminalProc (HWND hwnd, UINT msg,
655 WPARAM wParam, LPARAM lParam) {
658 char fontstatic[256];
662 CheckDlgButton (hwnd, IDC2_WRAPMODE, cfg.wrap_mode);
663 CheckDlgButton (hwnd, IDC2_WINNAME, cfg.win_name_always);
664 CheckDlgButton (hwnd, IDC2_DECOM, cfg.dec_om);
665 CheckDlgButton (hwnd, IDC2_LFHASCR, cfg.lfhascr);
666 SetDlgItemInt (hwnd, IDC2_ROWSEDIT, cfg.height, FALSE);
667 SetDlgItemInt (hwnd, IDC2_COLSEDIT, cfg.width, FALSE);
668 SetDlgItemInt (hwnd, IDC2_SAVEEDIT, cfg.savelines, FALSE);
669 fmtfont (fontstatic);
670 SetDlgItemText (hwnd, IDC2_FONTSTATIC, fontstatic);
671 CheckRadioButton (hwnd, IDC2_VTXWINDOWS, IDC2_VTPOORMAN,
672 cfg.vtmode == VT_XWINDOWS ? IDC2_VTXWINDOWS :
673 cfg.vtmode == VT_OEMANSI ? IDC2_VTOEMANSI :
674 cfg.vtmode == VT_OEMONLY ? IDC2_VTOEMONLY :
678 switch (LOWORD(wParam)) {
680 if (HIWORD(wParam) == BN_CLICKED ||
681 HIWORD(wParam) == BN_DOUBLECLICKED)
682 cfg.wrap_mode = IsDlgButtonChecked (hwnd, IDC2_WRAPMODE);
685 if (HIWORD(wParam) == BN_CLICKED ||
686 HIWORD(wParam) == BN_DOUBLECLICKED)
687 cfg.win_name_always = IsDlgButtonChecked (hwnd, IDC2_WINNAME);
690 if (HIWORD(wParam) == BN_CLICKED ||
691 HIWORD(wParam) == BN_DOUBLECLICKED)
692 cfg.dec_om = IsDlgButtonChecked (hwnd, IDC2_DECOM);
695 if (HIWORD(wParam) == BN_CLICKED ||
696 HIWORD(wParam) == BN_DOUBLECLICKED)
697 cfg.lfhascr = IsDlgButtonChecked (hwnd, IDC2_LFHASCR);
700 if (HIWORD(wParam) == EN_CHANGE)
701 MyGetDlgItemInt (hwnd, IDC2_ROWSEDIT, &cfg.height);
704 if (HIWORD(wParam) == EN_CHANGE)
705 MyGetDlgItemInt (hwnd, IDC2_COLSEDIT, &cfg.width);
708 if (HIWORD(wParam) == EN_CHANGE)
709 MyGetDlgItemInt (hwnd, IDC2_SAVEEDIT, &cfg.savelines);
711 case IDC2_CHOOSEFONT:
712 lf.lfHeight = cfg.fontheight;
713 lf.lfWidth = lf.lfEscapement = lf.lfOrientation = 0;
714 lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = 0;
715 lf.lfWeight = (cfg.fontisbold ? FW_BOLD : 0);
716 lf.lfCharSet = ANSI_CHARSET;
717 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
718 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
719 lf.lfQuality = DEFAULT_QUALITY;
720 lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
721 strncpy (lf.lfFaceName, cfg.font, sizeof(lf.lfFaceName)-1);
722 lf.lfFaceName[sizeof(lf.lfFaceName)-1] = '\0';
724 cf.lStructSize = sizeof(cf);
727 cf.Flags = CF_FIXEDPITCHONLY | CF_FORCEFONTEXIST |
728 CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
730 if (ChooseFont (&cf)) {
731 strncpy (cfg.font, lf.lfFaceName, sizeof(cfg.font)-1);
732 cfg.font[sizeof(cfg.font)-1] = '\0';
733 cfg.fontisbold = (lf.lfWeight == FW_BOLD);
734 cfg.fontheight = lf.lfHeight;
735 fmtfont (fontstatic);
736 SetDlgItemText (hwnd, IDC2_FONTSTATIC, fontstatic);
739 case IDC2_VTXWINDOWS:
744 (IsDlgButtonChecked (hwnd, IDC2_VTXWINDOWS) ? VT_XWINDOWS :
745 IsDlgButtonChecked (hwnd, IDC2_VTOEMANSI) ? VT_OEMANSI :
746 IsDlgButtonChecked (hwnd, IDC2_VTOEMONLY) ? VT_OEMONLY :
752 return GeneralPanelProc (hwnd, msg, wParam, lParam);
755 static int CALLBACK TelnetProc (HWND hwnd, UINT msg,
756 WPARAM wParam, LPARAM lParam) {
761 SetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype);
762 SetDlgItemText (hwnd, IDC3_TSEDIT, cfg.termspeed);
763 SetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username);
765 char *p = cfg.environmt;
767 SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_ADDSTRING, 0,
772 CheckRadioButton (hwnd, IDC3_EMBSD, IDC3_EMRFC,
773 cfg.rfc_environ ? IDC3_EMRFC : IDC3_EMBSD);
776 switch (LOWORD(wParam)) {
778 if (HIWORD(wParam) == EN_CHANGE)
779 GetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype,
780 sizeof(cfg.termtype)-1);
783 if (HIWORD(wParam) == EN_CHANGE)
784 GetDlgItemText (hwnd, IDC3_TSEDIT, cfg.termspeed,
785 sizeof(cfg.termspeed)-1);
788 if (HIWORD(wParam) == EN_CHANGE)
789 GetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username,
790 sizeof(cfg.username)-1);
794 cfg.rfc_environ = IsDlgButtonChecked (hwnd, IDC3_EMRFC);
797 if (HIWORD(wParam) == BN_CLICKED ||
798 HIWORD(wParam) == BN_DOUBLECLICKED) {
799 char str[sizeof(cfg.environmt)];
801 GetDlgItemText (hwnd, IDC3_VAREDIT, str, sizeof(str)-1);
806 p = str + strlen(str);
808 GetDlgItemText (hwnd, IDC3_VALEDIT, p, sizeof(str)-1-(p-str));
818 if ((p-cfg.environmt) + strlen(str) + 2 < sizeof(cfg.environmt)) {
820 p[strlen(str)+1] = '\0';
821 SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_ADDSTRING,
823 SetDlgItemText (hwnd, IDC3_VAREDIT, "");
824 SetDlgItemText (hwnd, IDC3_VALEDIT, "");
826 MessageBox(hwnd, "Environment too big", "PuTTY Error",
827 MB_OK | MB_ICONERROR);
832 if (HIWORD(wParam) != BN_CLICKED &&
833 HIWORD(wParam) != BN_DOUBLECLICKED)
835 i = SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_GETCURSEL, 0, 0);
841 SendDlgItemMessage (hwnd, IDC3_ENVLIST, LB_DELETESTRING,
868 return GeneralPanelProc (hwnd, msg, wParam, lParam);
871 static int CALLBACK SshProc (HWND hwnd, UINT msg,
872 WPARAM wParam, LPARAM lParam) {
875 SetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype);
876 SetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username);
877 CheckDlgButton (hwnd, IDC3_NOPTY, cfg.nopty);
878 CheckRadioButton (hwnd, IDC3_CIPHER3DES, IDC3_CIPHERBLOWF,
879 cfg.cipher == CIPHER_BLOWFISH ? IDC3_CIPHERBLOWF :
883 switch (LOWORD(wParam)) {
885 if (HIWORD(wParam) == EN_CHANGE)
886 GetDlgItemText (hwnd, IDC3_TTEDIT, cfg.termtype,
887 sizeof(cfg.termtype)-1);
890 if (HIWORD(wParam) == EN_CHANGE)
891 GetDlgItemText (hwnd, IDC3_LOGEDIT, cfg.username,
892 sizeof(cfg.username)-1);
895 if (HIWORD(wParam) == BN_CLICKED ||
896 HIWORD(wParam) == BN_DOUBLECLICKED)
897 cfg.nopty = IsDlgButtonChecked (hwnd, IDC3_NOPTY);
899 case IDC3_CIPHER3DES:
900 case IDC3_CIPHERBLOWF:
901 if (HIWORD(wParam) == BN_CLICKED ||
902 HIWORD(wParam) == BN_DOUBLECLICKED) {
903 if (IsDlgButtonChecked (hwnd, IDC3_CIPHER3DES))
904 cfg.cipher = CIPHER_3DES;
905 else if (IsDlgButtonChecked (hwnd, IDC3_CIPHERBLOWF))
906 cfg.cipher = CIPHER_BLOWFISH;
912 return GeneralPanelProc (hwnd, msg, wParam, lParam);
915 static int CALLBACK SelectionProc (HWND hwnd, UINT msg,
916 WPARAM wParam, LPARAM lParam) {
921 CheckRadioButton (hwnd, IDC4_MBWINDOWS, IDC4_MBXTERM,
922 cfg.mouse_is_xterm ? IDC4_MBXTERM : IDC4_MBWINDOWS);
924 static int tabs[4] = {25, 61, 96, 128};
925 SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_SETTABSTOPS, 4,
928 for (i=0; i<256; i++) {
930 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
931 (i>=0x21 && i != 0x7F) ? i : ' ',
933 SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_ADDSTRING, 0,
938 switch (LOWORD(wParam)) {
941 cfg.mouse_is_xterm = IsDlgButtonChecked (hwnd, IDC4_MBXTERM);
947 int n = GetDlgItemInt (hwnd, IDC4_CCEDIT, &ok, FALSE);
952 for (i=0; i<256; i++)
953 if (SendDlgItemMessage (hwnd, IDC4_CCLIST, LB_GETSEL,
957 SendDlgItemMessage (hwnd, IDC4_CCLIST,
958 LB_DELETESTRING, i, 0);
959 sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i,
960 (i>=0x21 && i != 0x7F) ? i : ' ',
962 SendDlgItemMessage (hwnd, IDC4_CCLIST,
972 return GeneralPanelProc (hwnd, msg, wParam, lParam);
975 static int CALLBACK ColourProc (HWND hwnd, UINT msg,
976 WPARAM wParam, LPARAM lParam) {
977 static const char *const colours[] = {
978 "Default Foreground", "Default Bold Foreground",
979 "Default Background", "Default Bold Background",
980 "Cursor Text", "Cursor Colour",
981 "ANSI Black", "ANSI Black Bold",
982 "ANSI Red", "ANSI Red Bold",
983 "ANSI Green", "ANSI Green Bold",
984 "ANSI Yellow", "ANSI Yellow Bold",
985 "ANSI Blue", "ANSI Blue Bold",
986 "ANSI Magenta", "ANSI Magenta Bold",
987 "ANSI Cyan", "ANSI Cyan Bold",
988 "ANSI White", "ANSI White Bold"
990 static const int permanent[] = {
991 TRUE, FALSE, TRUE, FALSE, TRUE, TRUE,
992 TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE,
993 TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE
997 CheckDlgButton (hwnd, IDC5_BOLDCOLOUR, cfg.bold_colour);
998 CheckDlgButton (hwnd, IDC5_PALETTE, cfg.try_palette);
1001 for (i=0; i<22; i++)
1002 if (cfg.bold_colour || permanent[i])
1003 SendDlgItemMessage (hwnd, IDC5_LIST, LB_ADDSTRING, 0,
1004 (LPARAM) colours[i]);
1006 SendDlgItemMessage (hwnd, IDC5_LIST, LB_SETCURSEL, 0, 0);
1007 SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[0][0], FALSE);
1008 SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[0][1], FALSE);
1009 SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[0][2], FALSE);
1012 switch (LOWORD(wParam)) {
1013 case IDC5_BOLDCOLOUR:
1014 if (HIWORD(wParam) == BN_CLICKED ||
1015 HIWORD(wParam) == BN_DOUBLECLICKED) {
1017 cfg.bold_colour = IsDlgButtonChecked (hwnd, IDC5_BOLDCOLOUR);
1018 n = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCOUNT, 0, 0);
1019 if (cfg.bold_colour && n!=22) {
1020 for (i=0; i<22; i++)
1022 SendDlgItemMessage (hwnd, IDC5_LIST,
1024 (LPARAM) colours[i]);
1025 } else if (!cfg.bold_colour && n!=12) {
1028 SendDlgItemMessage (hwnd, IDC5_LIST,
1029 LB_DELETESTRING, i, 0);
1034 if (HIWORD(wParam) == BN_CLICKED ||
1035 HIWORD(wParam) == BN_DOUBLECLICKED)
1036 cfg.try_palette = IsDlgButtonChecked (hwnd, IDC5_PALETTE);
1039 if (HIWORD(wParam) == LBN_DBLCLK ||
1040 HIWORD(wParam) == LBN_SELCHANGE) {
1041 int i = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCURSEL,
1043 if (!cfg.bold_colour)
1044 i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
1045 SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[i][0], FALSE);
1046 SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[i][1], FALSE);
1047 SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[i][2], FALSE);
1051 if (HIWORD(wParam) == BN_CLICKED ||
1052 HIWORD(wParam) == BN_DOUBLECLICKED) {
1053 static CHOOSECOLOR cc;
1054 static DWORD custom[16] = {0}; /* zero initialisers */
1055 int i = SendDlgItemMessage (hwnd, IDC5_LIST, LB_GETCURSEL,
1057 if (!cfg.bold_colour)
1058 i = (i < 3 ? i*2 : i == 3 ? 5 : i*2-2);
1059 cc.lStructSize = sizeof(cc);
1060 cc.hwndOwner = hwnd;
1061 cc.hInstance = hinst;
1062 cc.lpCustColors = custom;
1063 cc.rgbResult = RGB (cfg.colours[i][0], cfg.colours[i][1],
1065 cc.Flags = CC_FULLOPEN | CC_RGBINIT;
1066 if (ChooseColor(&cc)) {
1068 (unsigned char) (cc.rgbResult & 0xFF);
1070 (unsigned char) (cc.rgbResult >> 8) & 0xFF;
1072 (unsigned char) (cc.rgbResult >> 16) & 0xFF;
1073 SetDlgItemInt (hwnd, IDC5_RVALUE, cfg.colours[i][0],
1075 SetDlgItemInt (hwnd, IDC5_GVALUE, cfg.colours[i][1],
1077 SetDlgItemInt (hwnd, IDC5_BVALUE, cfg.colours[i][2],
1085 return GeneralPanelProc (hwnd, msg, wParam, lParam);
1088 static DLGPROC panelproc[NPANELS] = {
1089 ConnectionProc, KeyboardProc, TerminalProc,
1090 TelnetProc, SshProc, SelectionProc, ColourProc
1092 static char *panelids[NPANELS] = {
1093 MAKEINTRESOURCE(IDD_PANEL0),
1094 MAKEINTRESOURCE(IDD_PANEL1),
1095 MAKEINTRESOURCE(IDD_PANEL2),
1096 MAKEINTRESOURCE(IDD_PANEL3),
1097 MAKEINTRESOURCE(IDD_PANEL35),
1098 MAKEINTRESOURCE(IDD_PANEL4),
1099 MAKEINTRESOURCE(IDD_PANEL5)
1101 static char *names[NPANELS] = {
1102 "Connection", "Keyboard", "Terminal", "Telnet", "SSH", "Selection", "Colours"
1105 static int mainp[MAIN_NPANELS] = { 0, 1, 2, 3, 4, 5, 6 };
1106 static int reconfp[RECONF_NPANELS] = { 1, 2, 5, 6 };
1108 static int GenericMainDlgProc (HWND hwnd, UINT msg,
1109 WPARAM wParam, LPARAM lParam,
1110 int npanels, int *panelnums, HWND *page) {
1115 { /* centre the window */
1118 hw = GetDesktopWindow();
1119 if (GetWindowRect (hw, &rs) && GetWindowRect (hwnd, &rd))
1120 MoveWindow (hwnd, (rs.right + rs.left + rd.left - rd.right)/2,
1121 (rs.bottom + rs.top + rd.top - rd.bottom)/2,
1122 rd.right-rd.left, rd.bottom-rd.top, TRUE);
1125 { /* initialise the tab control */
1129 hw = GetDlgItem (hwnd, IDC_TAB);
1130 for (i=0; i<npanels; i++) {
1131 tab.mask = TCIF_TEXT;
1132 tab.pszText = names[panelnums[i]];
1133 TabCtrl_InsertItem (hw, i, &tab);
1135 /* *page = CreateDialogIndirect (hinst, panels[panelnums[0]].temp,
1136 hwnd, panelproc[panelnums[0]]);*/
1137 *page = CreateDialog (hinst, panelids[panelnums[0]],
1138 hwnd, panelproc[panelnums[0]]);
1139 SetWindowLong (*page, GWL_EXSTYLE,
1140 GetWindowLong (*page, GWL_EXSTYLE) |
1141 WS_EX_CONTROLPARENT);
1146 if (LOWORD(wParam) == IDC_TAB &&
1147 ((LPNMHDR)lParam)->code == TCN_SELCHANGE) {
1148 int i = TabCtrl_GetCurSel(((LPNMHDR)lParam)->hwndFrom);
1150 DestroyWindow (*page);
1151 /* *page = CreateDialogIndirect (hinst, panels[panelnums[i]].temp,
1152 hwnd, panelproc[panelnums[i]]);*/
1153 *page = CreateDialog (hinst, panelids[panelnums[i]],
1154 hwnd, panelproc[panelnums[i]]);
1155 SetWindowLong (*page, GWL_EXSTYLE,
1156 GetWindowLong (*page, GWL_EXSTYLE) |
1157 WS_EX_CONTROLPARENT);
1158 SetFocus (((LPNMHDR)lParam)->hwndFrom); /* ensure focus stays */
1162 /* case WM_CTLCOLORDLG: */
1163 /* return (int) GetStockObject (LTGRAY_BRUSH); */
1165 switch (LOWORD(wParam)) {
1168 EndDialog (hwnd, 1);
1173 EndDialog (hwnd, 0);
1178 EndDialog (hwnd, 0);
1184 static int CALLBACK MainDlgProc (HWND hwnd, UINT msg,
1185 WPARAM wParam, LPARAM lParam) {
1190 static HWND page = NULL;
1192 if (msg == WM_COMMAND && LOWORD(wParam) == IDOK) {
1195 * If the Connection panel is active and the Session List
1196 * box is selected, we treat a press of Open to have an
1197 * implicit press of Load preceding it.
1199 hw = GetDlgItem (hwnd, IDC_TAB);
1200 i = TabCtrl_GetCurSel(hw);
1201 if (panelproc[mainp[i]] == ConnectionProc &&
1202 page && implicit_load_ok) {
1203 SendMessage (page, WM_COMMAND,
1204 MAKELONG(IDC0_SESSLOAD, BN_CLICKED), 0);
1208 if (msg == WM_COMMAND && LOWORD(wParam) == IDC_ABOUT) {
1209 EnableWindow(hwnd, 0);
1210 DialogBox(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
1211 GetParent(hwnd), AboutProc);
1212 EnableWindow(hwnd, 1);
1214 return GenericMainDlgProc (hwnd, msg, wParam, lParam,
1215 MAIN_NPANELS, mainp, &page);
1218 static int CALLBACK ReconfDlgProc (HWND hwnd, UINT msg,
1219 WPARAM wParam, LPARAM lParam) {
1221 return GenericMainDlgProc (hwnd, msg, wParam, lParam,
1222 RECONF_NPANELS, reconfp, &page);
1225 static void get_sesslist(int allocate) {
1226 static char *buffer;
1227 int buflen, bufsize, i, ret;
1228 char otherbuf[2048];
1233 if (RegCreateKey(HKEY_CURRENT_USER,
1234 puttystr, &subkey1) != ERROR_SUCCESS)
1237 buflen = bufsize = 0;
1241 ret = RegEnumKey(subkey1, i++, otherbuf, sizeof(otherbuf));
1242 if (ret == ERROR_SUCCESS) {
1243 bufsize = buflen + 2048;
1244 buffer = srealloc(buffer, bufsize);
1245 unmungestr(otherbuf, buffer+buflen);
1246 buflen += strlen(buffer+buflen)+1;
1248 } while (ret == ERROR_SUCCESS);
1249 buffer = srealloc(buffer, buflen+1);
1250 buffer[buflen] = '\0';
1253 nsessions = 1; /* "Default Settings" counts as one */
1255 if (strcmp(p, "Default Settings"))
1261 sessions = smalloc(nsessions * sizeof(char *));
1262 sessions[0] = "Default Settings";
1266 if (strcmp(p, "Default Settings"))
1277 int do_config (void) {
1281 ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_MAINBOX), NULL, MainDlgProc);
1282 get_sesslist(FALSE);
1287 int do_reconfig (HWND hwnd) {
1291 backup_cfg = cfg; /* structure copy */
1292 ret = DialogBox (hinst, MAKEINTRESOURCE(IDD_RECONF), hwnd, ReconfDlgProc);
1294 cfg = backup_cfg; /* structure copy */
1298 void do_defaults (char *session) {
1300 load_settings (session, TRUE);
1302 load_settings ("Default Settings", FALSE);
1305 void lognegot (char *string) {
1306 if (nnegots >= negsize) {
1308 negots = srealloc (negots, negsize * sizeof(*negots));
1310 negots[nnegots] = smalloc(1+strlen(string));
1311 strcpy (negots[nnegots], string);
1314 SendDlgItemMessage (logbox, IDN_LIST, LB_ADDSTRING,
1318 void shownegot (HWND hwnd) {
1320 logbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_LOGBOX),
1322 ShowWindow (logbox, SW_SHOWNORMAL);
1326 void showabout (HWND hwnd) {
1328 abtbox = CreateDialog (hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
1330 ShowWindow (abtbox, SW_SHOWNORMAL);
1334 void verify_ssh_host_key(char *host, struct RSAKey *key) {
1335 char *keystr, *otherstr, *mungedhost;
1340 * Format the key into a string.
1342 len = rsastr_len(key);
1343 keystr = malloc(len);
1345 fatalbox("Out of memory");
1346 rsastr_fmt(keystr, key);
1349 * Now read a saved key in from the registry and see what it
1352 otherstr = malloc(len);
1353 mungedhost = malloc(3*strlen(host)+1);
1354 if (!otherstr || !mungedhost)
1355 fatalbox("Out of memory");
1357 mungestr(host, mungedhost);
1359 if (RegCreateKey(HKEY_CURRENT_USER, PUTTY_REG_POS "\\SshHostKeys",
1360 &rkey) != ERROR_SUCCESS) {
1361 if (MessageBox(NULL, "PuTTY was unable to open the host key cache\n"
1362 "in the registry. There is thus no way to tell\n"
1363 "if the remote host is what you think it is.\n"
1364 "Connect anyway?", "PuTTY Problem",
1365 MB_ICONWARNING | MB_YESNO) == IDNO)
1368 DWORD readlen = len;
1372 ret = RegQueryValueEx(rkey, mungedhost, NULL,
1373 &type, otherstr, &readlen);
1375 if (ret == ERROR_MORE_DATA ||
1376 (ret == ERROR_SUCCESS && type == REG_SZ &&
1377 strcmp(otherstr, keystr))) {
1378 if (MessageBox(NULL,
1379 "This host's host key is different from the\n"
1380 "one cached in the registry! Someone may be\n"
1381 "impersonating this host for malicious reasons;\n"
1382 "alternatively, the host key may have changed\n"
1383 "due to sloppy system administration.\n"
1384 "Replace key in registry and connect?",
1385 "PuTTY: Security Warning",
1386 MB_ICONWARNING | MB_YESNO) == IDNO)
1388 RegSetValueEx(rkey, mungedhost, 0, REG_SZ, keystr,
1390 } else if (ret != ERROR_SUCCESS || type != REG_SZ) {
1391 if (MessageBox(NULL,
1392 "This host's host key is not cached in the\n"
1393 "registry. Do you want to add it to the cache\n"
1394 "and carry on connecting?",
1396 MB_ICONWARNING | MB_YESNO) == IDNO)
1398 RegSetValueEx(rkey, mungedhost, 0, REG_SZ, keystr,